TwoSum Swift Solution - swift

I just started learning coding with swift, and was trying TwoSum.
"Given an array of integers, return indices of the two numbers such that they add up to a specific target.
You may assume that each input would have exactly one solution, and you may not use the same element twice.
Example:
Given nums = [2, 7, 11, 15], target = 9,
Because nums[0] + nums[1] = 2 + 7 = 9,
return [0, 1]."
I found some solutions from GitHub that I cannot understand.
code is from https://github.com/soapyigu/LeetCode-Swift/blob/master/Array/TwoSum.swift
class TwoSum {
func twoSum(_ nums: [Int], _ target: Int) -> [Int] {
var dict = [Int: Int]()
for (i, num) in nums.enumerated() {
if let lastIndex = dict[target - num] {
return [lastIndex, i]
}
dict[num] = i
}
fatalError("No valid outputs")
}
}
Could someone be so kind to explain to codes. Thanks a lot.

The dict initialised in the method stores the numbers in the input as keys, and their indices as values. The program uses this to remember which number is where. The dict can tell you things like "the number 2 is at index 0".
For each number num at index i in the input array, we subtract num from the target to find the other number that we need, in order for them to add up to target.
Now we have the other number we need, we check to see if we have seen such a number before, by searching dict. This is what the if let lastIndex = dict[target - num] part is doing. If the dict knows what index the other number is at, we return that index, and i.
If we haven't seen that number before, we record i into the dictionary under the key num, hoping that in later iterations, we can find a number that when added to num, makes 9.

Given an array of integers, return indices of the two numbers such that they add up to a specific target.
var arr:[Int] = []
func twoSum(_ nums: [Int], _ target: Int) -> [Int] {
var toggle = false
for i in 0..<nums.count {
for j in i+1..<nums.count {
if toggle == false {
if(nums[i]+nums[j]==target){
toggle = true
arr.insert(i, at: 0)
arr.insert(j, at: 1)
break
}
}
}
}
return arr
}
Example:
Given nums = [2, 7, 11, 15], target = 9,
Because nums[0] + nums[1] = 2 + 7 = 9,
return [0, 1].

In Sweeper's excellent answer, he explained what dict is used for: It lets you use a value from the array to find that value's index. It would be more obvious what the dictionary was used for if we called it indexes, and this code builds the same dictionary in a more explicit way:
var indexes = [Int: Int]()
for index in 0..<array.count {
let value = array[index]
indexes[value] = index
}
After that, you get a dictionary:
[2:0, 7:1, 11:2, 15:3]
You could write the function this way:
func twoSum(_ array: [Int], _ target: Int) -> [Int] {
var indexes = [Int: Int]()
for index in 0..<array.count {
let value = array[index]
indexes[value] = index
}
for index in 0..<array.count {
let value = array[index]
if let otherIndex = indexes[target - value],
index != otherIndex {
return [index, otherIndex]
}
}
fatalError("Unable to match values")
}
That is a much more long-winded (and less efficient) way of doing the same thing. It loops through the array twice instead of once, but the results should be the same.

func twoSum(array: [Int], target: Int) -> [Int] {
var dict = [Int:Int]()
for (index, number) in array.enumerated() {
let value = target - number
if let sum = dict[value] {
return [sum, index]
}
dict[number] = index
}
return [0,0]
}
/*
array=[1, 2, 3] -> target=4
enumerated() => [0,1], [1,2], [2,3]
(i, n)
v4 - 1 = 3
s[3:0]
s[3:0]
v4 - 2 = 2
s[2:0]
s[2:1]
v4 - 3 = 1
s[1:1]
s[1:2]
output [0,2]
*/

var numbers: [Int] = [1, 3, 6, 7, 7, 14, 12]
var target = 26
var result = [Int]()
for i in 0..<numbers.count {
for j in i+1..<numbers.count {
if numbers[i] + numbers[j] == target {
print(numbers[i],numbers[j])
result.append(i)
result.append(j)
}
}
}
print(Array(Set(result)))

func twoSum(_ nums: [Int], _ target: Int) -> [Int] {
var dict:[Int:Int] = [:]
for i in 0..<nums.count {
if dict[target - nums[i]] != nil {
return [dict[target - nums[i]] ?? 0, i]
} else {
dict[nums[i]] = i
}
}
return [0]
}

Here is a link to the discussion section of the TwoSum problem on Leetcode.
Lots of great Swift solutions there.
https://leetcode.com/problems/two-sum/discuss/?currentPage=1&orderBy=most_votes&query=swift.
My personal two cents -
func twoSumA(_ nums: [Int], _ target: Int) -> [Int] {
var numsHashMap: Dictionary<Int, Int> = [:]
var outputArr: [Int] = []
for index in 0..<nums.count {
let currentNum = nums[index]
if numsHashMap.keys.contains(target-currentNum) {
outputArr.append(numsHashMap[target-currentNum] ?? -1)
outputArr.append(index)
return outputArr
}
numsHashMap[currentNum] = index
}
return !outputArr.isEmpty ? outputArr : [-1, -1]
}

Related

Iterating based on a variable number of inner loops

In the below code I am trying to go through all possible combination of alphabets for number of characters which are runtime variable.
The purpose of this code is to build a kind of password cracker, which basically brute-force guess the string. I want to use loop, because I will be able to break the loop as soon as the correct combination is hit thus saving on time and resources which otherwise will be required if I try to build an array of all possible combinations in first step.
I have a static code which works for a string 5 characters long but in reality my string could be any length. How can I make my code work with any length of string?
let len = textField.text?.characters.count //Length of string
let charRange = "abcdefghijklmnopqrstuvwxyz" //Allowed characterset
for char1 in charRange.characters {
for char2 in charRange.characters {
for char3 in charRange.characters {
for char4 in charRange.characters {
for char5 in charRange.characters {
// Do whatever with all possible combinations
}
}
}
}
}
I think I have to utilize for totalChars in 1...len { somehow but can't figure out how the for loops are going to be created dynamically?
Idea: form the string using an array of indices into your alphabet; each time increment the indices.
[0, 0, 0] -> [1, 0, 0] -> [2, 0, 0] ->
[0, 1, 0] -> [1, 1, 0] -> [2, 1, 0] ->
[0, 2, 0] -> [1, 2, 0] -> [2, 2, 0] ->
[0, 0, 1] ... [2, 2, 2]
Here's an example using a length of 3 and an alphabet of abcd
let len = 3
let alphabet = "abcd".characters.map({ String($0) })
var allStrings = [String]()
let maxIndex = alphabet.endIndex
var indicies = Array(count: len, repeatedValue: 0)
outerLoop: while (true) {
// Generate string from indicies
var string = ""
for i in indicies {
let letter = alphabet[i]
string += letter
}
allStrings.append(string)
print("Adding \(string)")
// Increment the index
indicies[0] += 1
var idx = 0
// If idx overflows then (idx) = 0 and (idx + 1) += 1 and try next
while (indicies[idx] == maxIndex) {
// Reset current
indicies[idx] = 0
// Increment next (as long as we haven't hit the end done)
idx += 1
if (idx >= alphabet.endIndex - 1) {
print("Breaking outer loop")
break outerLoop
}
indicies[idx] += 1
}
}
print("All Strings: \(allStrings)")
As suggested by Martin R, you can use recursion
This is the function
func visit(alphabet:[Character], combination:[Character], inout combinations:[String], length: Int) {
guard length > 0 else {
combinations.append(String(combination))
return
}
alphabet.forEach {
visit(alphabet, combination: combination + [$0], combinations: &combinations, length: length - 1)
}
}
The helper function
func combinations(alphabet: String, length: Int) -> [String] {
var combinations = [String]()
visit([Character](alphabet.characters), combination: [Character](), combinations: &combinations, length: length)
return combinations
}
Test
Now if you want every combination of 3 chars, and you want "ab" as alphabet then
combinations("ab", length: 3) // ["aaa", "aab", "aba", "abb", "baa", "bab", "bba", "bbb"]
Duplicates
Please note that if you insert duplicates into your alphabet, you'll get duplicate elements into the result.
Time complexity
The visit function is invoked as many times as the nodes into a perfect k-ary tree with height h where:
k: the number of elements into the alphabet param
h: the length param
Such a tree has
nodes. And this is the exact number of times the function will be invoked.
Space complexity
Theoretically The max number of stack frames allocated at the same time to execute visit is length.
However since the Swift compiler does implement the Tail Call Optimization the number of allocated stack frames is only 1.
Finally we must consider that combinations will be as big as the number of results: alphabet^length
So the time complexity is the max of length and elements into the result.
And it is O(length + alphabet^length)
Update
It turns out you want a brute force password breaker so.
func find(alphabet:[Character], combination:[Character] = [Character](), length: Int, check: (keyword:String) -> Bool) -> String? {
guard length > 0 else {
let keyword = String(combination)
return check(keyword: keyword) ? keyword : nil
}
for char in alphabet {
if let keyword = find(alphabet, combination: combination + [char], length: length - 1, check: check) {
return keyword
}
}
return nil
}
The last param check is a closure to verify if the current word is the correct password. You will put your logic here and the find will stop as soon as the password is found.
Example
find([Character]("tabcdefghil".characters), length: 3) { (keyword) -> Bool in
return keyword == "cat" // write your code to verify the password here
}
Alternative to recursion; loop radix representation of incremental (repeated) traversing of your alphabet
An alternative to recursion is to loop over an numeral representation of your alphabet, using a radix representative for the different number of letters. A limitation with this method is that the String(_:,radix:) initializer allows at most base36 numbers (radix 36), i.e., you can at most perform your "password cracking" with a set of characters with a unique count <=36.
Help function
// help function to use to pad incremental alphabeth cycling to e.g. "aa..."
let padToTemplate: (str: String, withTemplate: String) -> String = {
return $0.characters.count < $1.characters.count
? String($1.characters.suffixFrom($0.characters.endIndex)) + $0
: $0
}
Main radix brute-force password checking method
// attempt brute-force attempts to crack isCorrectPassword closure
// for a given alphabet, suspected word length and for a maximum number of
// attempts, optionally with a set starting point
func bruteForce(isCorrectPassword: (String) -> Bool, forAlphabet alphabet: [Character], forWordLength wordLength: Int, forNumberOfAttempts numAttempts: Int, startingFrom start: Int = 0) -> (Int, String?) {
// remove duplicate characters (but preserve order)
var exists: [Character:Bool] = [:]
let uniqueAlphabet = Array(alphabet.filter { return exists.updateValue(true, forKey: $0) == nil })
// limitation: allows at most base36 radix
guard case let radix = uniqueAlphabet.count
where radix < 37 else {
return (-1, nil)
}
// begin brute-force attempts
for i in start..<start+numAttempts {
let baseStr = String(i, radix: radix).characters
.flatMap { Int(String($0), radix: radix) }
.map { String(uniqueAlphabet[$0]) }
.joinWithSeparator("")
// construct attempt of correct length
let attempt = padToTemplate(str: baseStr,
withTemplate: String(count: wordLength, repeatedValue: alphabet.first!))
// log
//print(i, attempt)
// test attempt
if isCorrectPassword(attempt) { return (i, attempt) }
}
return (start+numAttempts, nil) // next to test
}
Example usage
Example usage #1
// unknown content closure
let someHashBashing : (String) -> Bool = {
return $0 == "ask"
}
// setup alphabet
let alphabet = [Character]("abcdefghijklmnopqrstuvwxyz".characters)
// any success for 500 attempts?
if case (let i, .Some(let password)) =
bruteForce(someHashBashing, forAlphabet: alphabet,
forWordLength: 3, forNumberOfAttempts: 500) {
print("Password cracked: \(password) (attempt \(i))")
} /* Password cracked: ask (attempt 478) */
Example usage #2 (picking up one failed "batch" with another)
// unknown content closure
let someHashBashing : (String) -> Bool = {
return $0 == "axk"
}
// setup alphabet
let alphabet = [Character]("abcdefghijklmnopqrstuvwxyz".characters)
// any success for 500 attempts?
let firstAttempt = bruteForce(someHashBashing, forAlphabet: alphabet,
forWordLength: 3, forNumberOfAttempts: 500)
if let password = firstAttempt.1 {
print("Password cracked: \(password) (attempt \(firstAttempt.0))")
}
// if not, try another 500?
else {
if case (let i, .Some(let password)) =
bruteForce(someHashBashing, forAlphabet: alphabet,
forWordLength: 3, forNumberOfAttempts: 500,
startingFrom: firstAttempt.0) {
print("Password cracked: \(password) (attempt \(i))")
} /* Password cracked: axk (attempt 608) */
}

Group dictionary by key in Swift

I'm trying to implement a groupBy functionality where all the numbers of a nested list are grouped. My code so far:
struct MyClass {
var numbers: [Int]
...
}
var dict: [String : MyClass] = ...
let numbers = dict
.filter{ $0.0.containsString(searchString) }
.flatMap{ $0.1.numbers }
This yields me an Array of Ints. However I'd like to have a dictionary [Int : Int] with each unique number and the count of its occurence. So for example:
[1,2,3,4,1,2,2,1]
should be:
[1 : 2, 2 : 3, 3 : 1, 4 : 1]
I know there's a groupBy operator, but Swift doesn't seem to have one. I've tried with reduce:
func reducer(accumulator: [Int: Int], num: Int) -> [Int : Int] {
var acc = accumulator
acc[num]! += 1
return acc
}
filtered.reduce([:], combine: reducer)
But it crashes when I want to run it. Not sure why, I get a EXC_BAD_INSTRUCTION.
I'd appreciate any help.
let numbers = [1,2,3,4,1,2,2,1]
var results = [Int: Int]()
Set(numbers).forEach { number in results[number] = numbers.filter { $0 == number }.count }
print(results) // [2: 3, 3: 1, 1: 3, 4: 1]
Actually I'm not very sure if this is what you want. I just looked at your examples.
Using NSCountedSet:
var objects = [1,2,3,4,1,2,2,1]
let uniques = NSCountedSet(array: objects)
uniques.forEach { results[$0 as! Int] = uniques.countForObject($0) }
print(results) // [2: 3, 3: 1, 1: 3, 4: 1]
I would expect the crash to be ocurring on this line:
acc[num]! += 1
The first time this is called for a number, the entry doesn't exist in the dictionary yet so acc[num] is nil. Forcefully unwrapping it would cause a crash.
Not sure if this is the best solution but you can simple check for this case:
if (acc[num]) {
acc[num]! += 1
} else {
acc[num] = 1
}
Cleaner code from #vacawama in the comments:
acc[num] = (acc[num] ?? 0) + 1
Here's an extension to Array that does what you're asking:
extension Array where Element: Hashable {
var grouped: [Element:Int] {
var dict = [Element:Int]()
self.forEach { dict[$0] = (dict[$0] ?? 0) + 1 }
return dict
}
}
The key is the closure: { dict[$0] = (dict[$0] ?? 0) + 1 }.
It takes the current value in the array, tests to see if it's a key in the dictionary, returns the value for that key if it exists or 0 if it doesn't, then adds one and sets the key:value to be the pair of the current value and occurrences so far.
Example use:
[1,2,3,4,1,2,2,1].grouped // => [2: 3, 3: 1, 1: 3, 4: 1]
You need something like this:
if let _ = acc.indexForKey(num) {
acc[num]! += 1
}
else {
acc[num] = 1
}
It's sort of unclear what you're asking for, but here's a function that will take an array of ints and return a dictionary with the number as the key, and the count as the value:
func getDictionaryOfCounts(accumulator: [Int]) -> [Int : Int] {
var countingDictionary: [Int : Int] = [:]
accumulator.forEach { (value) in
if countingDictionary[value] != nil {
countingDictionary[value]! += 1
}
else{
countingDictionary[value] = 1
}
}
return countingDictionary
}

Swift: second occurrence with indexOf

let numbers = [1,3,4,5,5,9,0,1]
To find the first 5, use:
numbers.indexOf(5)
How do I find the second occurence?
List item
You can perform another search for the index of element at the remaining array slice as follow:
edit/update: Swift 5.2 or later
extension Collection where Element: Equatable {
/// Returns the second index where the specified value appears in the collection.
func secondIndex(of element: Element) -> Index? {
guard let index = firstIndex(of: element) else { return nil }
return self[self.index(after: index)...].firstIndex(of: element)
}
}
extension Collection {
/// Returns the second index in which an element of the collection satisfies the given predicate.
func secondIndex(where predicate: (Element) throws -> Bool) rethrows -> Index? {
guard let index = try firstIndex(where: predicate) else { return nil }
return try self[self.index(after: index)...].firstIndex(where: predicate)
}
}
Testing:
let numbers = [1,3,4,5,5,9,0,1]
if let index = numbers.secondIndex(of: 5) {
print(index) // "4\n"
} else {
print("not found")
}
if let index = numbers.secondIndex(where: { $0.isMultiple(of: 3) }) {
print(index) // "5\n"
} else {
print("not found")
}
Once you've found the first occurrence, you can use indexOf on the remaining slice of the array to locate the second occurrence:
let numbers = [1,3,4,5,5,9,0,1]
if let firstFive = numbers.indexOf(5) { // 3
let secondFive = numbers[firstFive+1..<numbers.count].indexOf(5) // 4
}
I don't think you can do it with indexOf. Instead you'll have to use a for-loop. A shorthand version:
let numbers = [1,3,4,5,5,9,0,1]
var indexes = [Int]()
numbers.enumerate().forEach { if $0.element == 5 { indexes += [$0.index] } }
print(indexes) // [3, 4]
Here's a general use extension of Array that will work for finding the nth element of a kind in any array:
extension Array where Element: Equatable {
// returns nil if there is no nth occurence
// or the index of the nth occurence if there is
func findNthIndexOf(n: Int, thing: Element) -> Int? {
guard n > 0 else { return nil }
var count = 0
for (index, item) in enumerate() where item == thing {
count += 1
if count == n {
return index
}
}
return nil
}
}
let numbers = [1,3,4,5,5,9,0]
numbers.findNthIndexOf(2, thing: 5) // returns 4
EDIT: as per #davecom's comment, I've included a similar but slightly more complex solution at the bottom of the answer.
I see a couple of good solutions here, especially considering the limitations the relatively new language of Swift. There is a really concise way to do it too, but beware...it is rather quick-and-dirty. May not be the perfect solution, but it is pretty quick. Also very versatile (not to brag).
extension Array where Element: Equatable {
func indexes(search: Element) -> [Int] {
return enumerate().reduce([Int]()) { $1.1 == search ? $0 + [$1.0] : $0 }
}
}
Using this extension, you could access the second index as follows:
let numbers = [1, 3, 4, 5, 5, 9, 0, 1]
let indexesOf5 = numbers.indexes(5) // [3, 4]
indexesOf5[1] // 4
And you're done!
Basically, the method works like this: enumerate() maps the array to tuples including the index of each element with the element itself. In this case, [1, 3, 4, 5, 5, 9, 0, 1].enumerate() returns a collection of the type EnumerateSequence<Array<Int>> which, translated to an Integer array, returns [(0,1), (1,3), (2,4), (3,5), (4,5), (5,9), (6,0), (7,1)].
The rest of the work is done using reduce (called 'inject' in some languages), which is an extremely powerful tool that many coders are not familiar with. If the reader is among those coders, I'd recommend checking out this article regarding use of the function in JS (keep in mind the placement of the non-block argument passed in is inputted after the block in JS, rather than before as seen here).
Thanks for reading.
P.S. not to be too long-winded on this relatively simple solution, but if the syntax for the indexes method shown above is a bit too quick-and-dirty, you could try something like this in the method body, where the closure's parameters are expanded for a bit more clarity:
return enumerate().reduce([Int]()) { memo, element in
element.1 == search ? memo + [element.0] : memo
}
EDIT: Here's another option that allows the implementer to scan for a specific "index at index" (e.g. the second occurrence of 5) for a more efficient solution.
extension Array where Element: Equatable {
func nIndex(search: Element, n: Int) -> Int? {
let info = enumerate().reduce((count: 0, index: 0), combine: { memo, element in
memo.count < n && element.1 == search ? (count: memo.count + 1, index: element.0) : memo
})
return info.count == n ? info.index : nil
}
}
[1, 3, 4, 5, 5, 9, 0, 1].nIndex(5, n: 2) // 4
[1, 3, 4, 5, 5, 9, 0, 1].nIndex(5, n: 3) // nil
The new method still iterates over the entire array, but is much more efficient due to the lack of "array-building" in the previous method. That performance hit would be negligible with the 8-object array used for the majority. But consider a list of 10,000 random numbers from 0 to 99:
let randomNumbers = (1...10000).map{_ in Int(rand() % 100)}
let indexes = randomNumbers.indexes(93) // count -> 100 (in my first run)
let index1 = indexes[1] // 238
// executed in 29.6603130102158 sec
let index2 = randomNumbers.nIndex(93, n: 2) // 238
// executed in 3.82625496387482 sec
As can be seen, this new method is considerably faster with the (very) large dataset; it is a bit more cumbersome and confusing though, so depending on your application, you may prefer the simpler solution, or a different one entirely.
(Again) thanks for reading.
extension Collection where Element: Equatable {
func nth(occurance: Int, of element: Element) -> Index? {
var level : Int = occurance
var position = self.startIndex
while let index = self[position...].index(of: element) {
level -= 1
guard level >= 0 else { return nil }
guard level != 0 else { return index }
position = self.index(after: index)
}
return nil
}
}

Count elements of array matching condition in Swift

I'm basically looking for the swift equivalent of the follow c++ code:
std::count_if(list.begin(), list.end(), [](int a){ return a % 2 == 0; }); // counts instances of even numbers in list
My problem isn't actually searching for even numbers, of course; simply the general case of counting instances matching a criterion.
I haven't seen a builtin, but would love to hear that I simply missed it.
Like this:
let a: [Int] = ...
let count = a.filter({ $0 % 2 == 0 }).count
An alternative to Aderstedt's version
let a = [ .... ]
let count = a.reduce(0){
(count, element) in
return count + 1 - element % 2
}
My intuition says my way will be faster because it doesn't require the creation of a second array. However, you'd need to profile both methods to be sure.
Edit
Following MartinR's comment about generalisation of the function, here it is
extension SequenceType
{
func countMatchingCondition(condition: (Self.Generator.Element) -> Bool) -> Int
{
return self.reduce(0, combine: { (count, e) in count + (condition(e) ? 1 : 0) })
}
}
let a = [1, 2, 3, 3, 4, 12].countMatchingCondition { $0 % 2 == 0 }
print("\(a)") // Prints 3
Default array:
let array: [Int] = [10, 10, 2, 10, 1, 2, 3]
filter(_:) method
let countOfTen = array.filter({ $0 == 10 }).count // 3
count(where:) method
Update: This Swift 5.0 feature was withdrawn in beta testing because it was causing performance issues for the type checker.
let countOfTen = array.count(where: { $0 == 10 }) // 3
You can use Collection.lazy to have the simplicity of Aderstedt's Answer but with O(1) space.
let array = [1, 2, 3]
let count = array.lazy.filter({ $0 % 2 == 0 }).count
The most compact reduce statement that will do this is:
let a = Array(1 ... 20)
let evencount = a.reduce(0) { $0 + ($1 % 2 == 0 ? 1 : 0) }
Reduce takes two variables: starts with 0 (var $0) then for every element in Array a (var $1) if the value is divisible by 2 with no remainder then add one to your count.
This is also efficient as it does not create an additional array unlike using a.filter(){}.count .
You can also do this with reduce()
let a = Array(1 ... 20)
let evenCount = a.reduce(0) { (accumulator, value) -> Int in
guard value % 2 == 0 else { return accumulator }
return accumulator + 1
}
Almost everything you want to do with the map() and filter functions can actually be done with a reduce although it's not always the most readable.
Swift 5 or later:
public extension Sequence {
func occurrences(where predicate: (Element) throws -> Bool) rethrows -> Int {
try reduce(0) { try predicate($1) ? $0 + 1 : $0 }
}
}
public extension Sequence where Element: Equatable {
func occurrences(of element: Element) -> Int {
reduce(0) { element == $1 ? $0 + 1 : $0 }
}
}
let multiplesOf2 = [1,2,3,4,4,5,4,5].occurrences{$0.isMultiple(of: 2)} // 4
"abcdeabca".occurrences(of: "a") // 3
extension BinaryInteger {
var isOdd: Bool { !isMultiple(of: 2) }
var isEven: Bool { isMultiple(of: 2) }
}
(-4).isOdd // false
(-3).isOdd // true
(-2).isOdd // false
(-1).isOdd // true
0.isOdd // false
1.isOdd // true
2.isOdd // false
3.isOdd // true
4.isOdd // false
(-4).isEven // true
(-3).isEven // false
(-2).isEven // true
(-1).isEven // false
0.isEven // true
1.isEven // false
2.isEven // true
3.isEven // false
4.isEven // true
let odds = [1,2,3,4,4,5,5,11].occurrences(where: \.isOdd) // 5
let evens = [1,2,3,4,4,5,5,11].occurrences(where: \.isEven) // 3

Change specific values in an array

I have 3 arrays of type Int that have 5 values in each in them. I'm trying to create a function that replaces the values based on conditions. For example, array1, if a value of an index is between 2-5, replace with a randomly generated number between 1-6.
Here is what I have so far
import Foundation
func newRandomNumbers(#array1: [Int], array2: [Int], array3: [Int]) {
for i in 0..<5 {
switch (array1[i]) {
case 2, 3, 4, 5:
let randomNumber = Int(1 + arc4random() % 6)
array1[i] = randomNumber
break;
default:
break;
}
switch (array2[i]) {
case 2, 3, 4, 5:
array2[i]
break;
default:
break;
}
switch (array3[i]) {
case 1, 2, 3, 4, 5:
array3[i]
break;
default:
break;
}
}
}
I get an error " Cannot assign to immutable value of type 'Int'"
When I rewrite a simplified function that does the same purpose I don't get the error, but strangely not all the numbers are replaced.
import Foundation
var newArray = [2,3,4,5,6]
func newRandom(#array1: [Int]){
for i in 0..<5 {
switch(array1[i]) {
case 2, 3, 4, 5:
let randomNumber = Int(1 + arc4random() % 6)
newArray[1] = randomNumber
default:
break;
}
}
}
newRandom(array1: newArray)
newArray
Not sure how to resolve. Recommendations on how to clean up my code would also be appreciated. Thanks!
"Cannot assign to immutable value of type 'Int'" is because the parameters are actually constants. You can read the line:
func newRandomNumbers(#array1: [Int], array2: [Int], array3: [Int])
as:
func newRandomNumbers(#array1 let array1: [Int], let array2: [Int], let array3: [Int])
You can change it by putting var in front of the parameter and return the array. Another option is using & to make it a reference, so you don't have to return a new array.
I would suggest you look into the array's map function:
https://developer.apple.com/library/ios/documentation/General/Reference/SwiftStandardLibraryReference/Array.html
you would use for example:
array.map {
if ($0 satisfies condition) {
generate random number
}
}
You can use inout for each of your function parameters and add & before your variable name when calling the function, it will modify the array in place:
func newRandom(inout myArray: [Int]) {
for (index, element) in enumerate(myArray) {
switch element {
case 2...5:
myArray[index] = Int(1 + arc4random() % 6)
default:
break
}
}
}
var newArray = [2,3,4,5,6]
newRandom(&newArray)
println(newArray) // "newArray" was modified, contains random numbers
Note:
switch element {
case 2...5:
is equivalent to:
if element >= 2 && element <= 5 {
SWIFT 2.0 UPDATE:
As of Swift 2.0, enumerate is now to be called on the sequence itself. Also, println has been deprecated in favor of print:
func newRandom(inout myArray: [Int]) {
for (index, element) in myArray.enumerate() {
switch element {
case 2...5:
myArray[index] = Int(1 + arc4random() % 6)
default:
break
}
}
}
var newArray = [2,3,4,5,6]
newRandom(&newArray)
print(newArray)