Iterate through an array to find pairs of values

Martin Muldoon Source

I have a sorted array. I would like to iterate through the array and increment a counter as I find pairs of values. I'm not finding an elegant solution to this.

var pairs = 0
    let colors = [10, 20, 20, 10, 10, 30, 50, 10, 20
    let sortedColors = colors.sorted{ $0 < $1}
    // [10, 10, 10, 10, 20, 20, 20, 30, 50] -> pairs should equal 3

    for i in 0..<colors.count - 1 {
        if sortedColors[i+1] != colors.count && sortedColors[i] == sortedColors[i+1] {
            pairs += 1
        } 
    }

print(pairs)
swift

Answers

answered 3 months ago Sulthan #1

I would just count the repetitions and then divide the number of repetitions by 2 to count the pairs. For example, if a number appears 3 times, there is one pair:

let colors = [10, 20, 20, 10, 10, 30, 50, 10, 20]

let countedSet = NSCountedSet(array: colors)
let pairs = countedSet.map { countedSet.count(for: $0) / 2 }.reduce(0, +)
print(pairs) // 3

Unfortunately, there is no Swift CountedSet yet :(

answered 3 months ago dfri #2

An alternative but similar approach as @Sulthan's answer is to use a dictionary to count occurrences rather than NSCountedSet:

let colors = [10, 20, 20, 10, 10, 30, 50, 10, 20]
let numberOfPairs = colors
  .reduce(into: [:]) { counts, num in counts[num, default: 0] += 1 }
  .reduce(0) { cumsum, kv in cumsum + kv.value / 2 } // 3

Or, using shorthand argument names in the two closures:

let numberOfPairs = colors
  .reduce(into: [:]) { $0[$1, default: 0] += 1 }
  .reduce(0) { $0 + $1.value / 2 }

Where above, for the number occurrence count, we make use of @vacawama's answer in the Q&A that I initially used as target for dupe-marking this Q&A.

answered 3 months ago Sandeep #3

You could as well use new Dictionary syntax like so,

With grouping syntax,

let pairs = Dictionary(grouping: colors){ $0 }
                        .map { $1.count / 2 }
                        .reduce(0, +)
print(pairs)

With uniquing syntax,

let pairs = Dictionary( zip( colors, Array(repeating: 1, count: colors.count)),
                       uniquingKeysWith: +)
                      .reduce(0, { $0 + $1.1 / 2})

comments powered by Disqus