2

Need to loop through an array and say whether there are any pairs of numbers that sum to 8

e.g. [1,2,4,4] = yes

Can get it working with lots of nested if statements but this will be impractical if the array changes.

What I'd ideally like to do is say for i if i + (i.indexPosition +1 {Number next to i})) == 8 then print true, if not false, then move onto the next iteration of numbersSet

Wondering if someone knew some better logic that could be used here? Many thanks!!

E.g.

var numbersSet = [1, 2, 4, 4]

for i in numbersSet2 {

    var targetSum = 8

    if i + numbersSet2[1] == targetSum {

        print("True")
    } else { // Nested if statements here

        print("False")
    }
}
Hamish
  • 78,605
  • 19
  • 187
  • 280
jpazzajpeg
  • 133
  • 2
  • 9

4 Answers4

3

You want to check all sums numbers[i] + numbers[j] where i < j, and the easiest way to do so is a nested loop like this:

func checkPairs(in numbers: [Int], forSum target: Int) -> Bool {

    for i in 0..<numbers.count {
        for j in i+1..<numbers.count {
            if numbers[i] + numbers[j] == target {
                return true
            }
        }
    }
    return false
}

The array lookups can be avoided by using the enumerated() method and array slices:

func checkPairs(in numbers: [Int], forSum target: Int) -> Bool {

    for (i, x) in numbers.enumerated() {
        for y in numbers[i+1 ..< numbers.count] {
            if x + y == target {
                return true
            }
        }
    }
    return false
}

Here x is the current element of the outer loop and i its index. y is the current element of the inner loop which starts enumerating at i + 1.

Example:

print(checkPairs(in: [1, 2, 4, 4], forSum: 8))
print(checkPairs(in: [1, 2, 4, 4], forSum: 7))

The above function could be written more compactly as

func checkPairs(in numbers: [Int], forSum target: Int) -> Bool {

    return numbers.enumerated().contains(where: { (i, x) -> Bool in
        numbers[i+1 ..< numbers.count].contains(target - x)
    })
}

If the given numbers are in non-decreasing order then you can improve the performance by terminating the inner loop if the target sum cannot be reached:

func checkPairs(in numbers: [Int], forSum target: Int) -> Bool {

    for (i, x) in numbers.enumerated() {
        for y in numbers[i+1 ..< numbers.count] {
            if x + y == target {
                return true
            }
            if x + y > target {
                break
            }
        }
    }
    return false
}

For an array of non-decreasing numbers an even more efficient solution would be to do a binary search for target - x for each array element x. Here is a possible binary search implementation (a variant of https://stackoverflow.com/a/40226976/1187415):

extension Collection where Iterator.Element: Comparable {

    func binarySearch(element: Iterator.Element) -> Bool {
        var low = startIndex
        var high = endIndex
        while low != high {
            let mid = index(low, offsetBy: distance(from: low, to: high)/2)
            if self[mid] < element {
                low = index(after: mid)
            } else if element < self[mid] {
                high = mid
            } else {
                return true
            }
        }
        return false
    }
}

which can then be used as

func checkPairs(in numbers: [Int], forSum target: Int) -> Bool {

    return numbers.enumerated().contains(where: { (i, x) -> Bool in
        numbers[i+1 ..< numbers.count].binarySearch(element: target - x)
    })
}
Community
  • 1
  • 1
Martin R
  • 529,903
  • 94
  • 1,240
  • 1,382
2

Above all answers are fine but all are returning Bool value, Thus I am writing a solution to store all possible pairs in a dictionary and print them.

The below solution will avoid reiteration, Thus complexity is minimized.

var numbers = [13,2,4,5,6,3,7,90,11,10,12,1,8,9]
var dictionary1 : [Int : Int] = [:]
var j = 0
func findPair(numbers : [ Int ] , number : Int) -> [Int : Int] {
    
    for (i , _) in numbers.enumerated() {
        
        j = i
        while j < numbers.count {
            
            if i != j {
                let addition = numbers[i] + numbers[j]
                if addition == number {
                    dictionary1[numbers[i]] = numbers[j]
                }
            }
            j += 1
        }
    }
    return dictionary1
}

let result = findPair(numbers: numbers, number: 11)
print(dictionary1)

Output - [10: 1, 4: 7, 5: 6, 3: 8, 2: 9]

These are all pairs whose addition is a given number. i.e 11

Shrikant Phadke
  • 358
  • 2
  • 11
1

You can use nested for loops with indexes:

for (firstIndex, firstElement) in numbersSet.enumerated() {
    for (secondIndex, secondElement) in numbersSet.enumerated() {
        if firstIndex != secondIndex && firstElement + secondElement == 8 {
            return true
        }
    }
}
raver
  • 263
  • 6
  • 14
0

Using two pointer technique.

Time Complexity: O(n)

Other solutions mentioned here have Time Complexity: O(n2)

func isPairSum()-> Bool{

let array = [3, 5, 9, 2, 8, 10, 11]
let sum = 22


var i = 0
var j = array.count - 1

while i<j {
    
    let valueSum = array[i] + array[j]
    if valueSum == sum {
        return true
    }
    
    else if valueSum > sum {
        j -= 1
    }
    
    else if valueSum < sum {
        i += 1
    }
    
}
return false

}

And If you want the values of the pair, instead of returning Bool, you can return Tuple of type Int.

Tabish Sohail
  • 1,040
  • 2
  • 9
  • 22