Swift: Iterate through array and count Ints equal to 5 - ios

In Swift how would I iterate through the NSMutableArray of ints var numbers = [4,5,5,4,3] and count how many are equal to 5?

You can use reduce for this:
let array = [4,5,5,4,3]
let fives = array.reduce(0, combine: { $0 + Int($1 == 5) })

One possible solution:
numbers.filter {$0 == 5}.count

Related

how to store values in a 1D array into a 2D array in Swift 4

Hi I would like to store values of a 1D array into a 2D array.
My 1D array has 50 elements and I want to store it in a 5x10 array, but whenever I do that, it always gives me a "Index out of range" error
Any help would be appreciated thanks!
var info2d = [[String]]()
var dataArray = outputdata.components(separatedBy: ";")
for j in 0...10 {
for i in 0...5 {
info2d[i][j] = dataArray[(j)*5+i]
print(info2d[i][j])
}
}
Lots of error in your code.
info2d must be initialised with default values before using it by index
// initialising 2d array with empty string value
var info2d = [[String]](repeating: [String](repeating: "", count: 10), count: 5)
Secondly for loop with ... includes the last value too, use ..<
for j in 0..<10 {
//...
}
Thirdly (j)*5+i is incorrect too.
Better Read how to use arrays, collections and for loop in swift.
https://docs.swift.org/swift-book/LanguageGuide/ControlFlow.html
https://docs.swift.org/swift-book/LanguageGuide/CollectionTypes.html
I would make use of ArraySlice for this.
var arr2D = [[String]]()
for i in 0..<5 {
let start = i * 10
let end = start + 10
let slice = dataArray[start..<end] //Create an ArraySlice
arr2D.append(Array(slice)) //Create new Array from ArraySlice
}

add a range of objects from one array to another

Currently we have 2 arrays:
fileprivate var totalDrinksArray: [CocktailModel] = []
fileprivate var currentDrinksArray: [CocktailModel] = []
What I'm trying to do is get the first 2 objects of the totalDrinksArray and add them to the currentDrinksArray. After a button is pressed the next 2 drinks will be added from the totalDrinksArray to the currentDrinksArray (for a total of 4 drinks )and so on.
You can use Array method func prefix(_ maxLength: Int) which will return a slice of the total array (up to n elements) or less if there is not enough elements and append the contents to your current array or insert it at the desired index:
currentDrinksArray.append(contentsOf: totalDrinksArray.prefix(2))
Or if you would like to insert them in the beginning of your array:
currentDrinksArray.insert(contentsOf: totalDrinksArray.prefix(2), at: 0)
You can "add" arrays together:
currentDrinksArray += totalDrinksArray[0...1]
should work.
Not quite clear from your question, but if you want to "add the next two" (the 3rd and 4th):
currentDrinksArray += totalDrinksArray[2...3]
Simplest safe solution IMO:
var currentIndex = 0
func addDrinks() {
if(currentIndex + 2 >= totalDrinksArray.count) {
currentDrinksArray += totalDrinksArray[currentIndex...]
}
else {
currentDrinksArray += totalDrinksArray[currentIndex..<(currentIndex + 2)]
}
currentIndex += 2
}

App crashes within for loop in swift 3

Here I am just getting array count and using for loop but got crashed at let arr = arrayAdaptor[i] this line after completing my array count don't know why it's crashing can anyone help me how to resolve this
var arrayAdaptor = [Struct_Row_Rating]()
for i in 0...arrayAdaptor.count {
let arr = arrayAdaptor[i]
let number = arr.row
let row = number + 1
dict.updateValue("\(arr.rating)", forKey: "\(row)")
print(dict)
}
struct Struct_Row_Rating {
var row: Int
var rating: Double
init(row: Int , rating: Double) {
self.row = row
self.rating = rating
}}
The operator ... exceeds the range of the array. You have to write
for i in 0..<arrayAdaptor.count
or
for i in 0...arrayAdaptor.count - 1
Basically don't use these index based for loops in Swift at all.
Use Fast Enumeration:
for arr in arrayAdaptor {
and if you really need the index
for (index, arr) in arrayAdaptor.enumerated() {
Why you are using 0...arrayAdaptor.count range style avoid it and Simply Use enumerated() of an Array:
for (_,value) in arrayAdaptor.enumerated() {
let number = value.row
let row = number + 1
dict.updateValue("\(arr.rating)", forKey: "\(row)")
print(dict)
}
If you don't want any index to try with this:
for value in arrayAdaptor {
let number = value.row
let row = number + 1
dict.updateValue("\(arr.rating)", forKey: "\(row)")
print(dict)
}
See this
One of the options not mentioned in the answers is forEach approach.
arrayAdaptor.forEach { item in
print(item)
}
or
arrayAdaptor.forEach {
print($0) // without named parameter
}
// Your case:
arrayAdaptor.forEach { item in
let arr = item
let number = item.row
let row = number + 1
dict.updateValue("\(arr.rating)", forKey: "\(row)")
print(dict)
}
This is pretty much the same as the handy for..in mentioned in vadian's answer:
for arr in arrayAdaptor { ... }
From Swift 4 you can use One sided ranges.
i... is favored over i..< because the latter is ugly. We have to pick one, two would be redundant and likely to cause confusion over which is the "right" one. Either would be reasonable on pedantic correctness grounds – (i as Int)... includes Int.max consistent with ..., whereas a[i...] is interpreted as a[i..<a.endIndex] consistent with i..<.
Example:
var names = ["Jack", "New", "peter"]
let first = names[0...]
let second = names[..<names.count]
print(first)//prints ["Jack", "New", "peter"]
print(second)//prints ["Jack", "New", "peter"]
You can also iterate loop by 'map' function:
let _ = arrayAdaptor.map({ adaptor in
let number = adaptor.row
let row = number + 1
dict.updateValue("\(adaptor.rating)", forKey: "\(row)")
print(dict)
})

Swift 3 For loop compare and change

Here is my code so far
var counter = 0
for i in 0...9 {
var val = NamePicker()
// array to find duplicates
var buttonValues = ["", "", "", "", "", "", "", "", "", ""] // array for button names
buttonValues.insert(val, at: counter)
print(buttonValues[counter])
counter += 1
}
This code is putting 10 string values into my array. What I would like to do is find a way to check each value in my array. for eample if my end result array is ["a","a","a","b","b","c","c","e","f","c"] I want to see if there is a triple of the same name(single and duplicates are fine). However if there is a triple I would like to change the 3rd value to another val from my NamePicker() function.
so with my array of
["a","a","a","b","b","c","c","e","f","c"]
there are 3 "a" and 3 "c", having two of the same is ok, i would like to change the 3rd to a new values and if the new value makes another triple it will change until there are no more triples.
so that array could possible have an end result of
["a","a","f","b","b","c","c","e","f","z"]
this is where the triples where changed.
Any help on how to do this efficiently?
Both options below asume that your NamePciker() function can generate at least 5 distinct values so there exists an array that satisfies your requirement.
Your requirement is better handled by not generating so many duplicates to begin with. If all you want is an array of names when each name cannot be repeated more than twice, try this:
var buttonValues = [String]()
var dict = [String: Int]()
while buttonValues.count < 10 {
let name = NamePicker()
let count = dict[name] ?? 0
guard count < 2 else { continue }
buttonValues.append(name)
dict[name] = count + 1
}
If you already have the array and want to correct it, do this:
var buttonValues = ["a","a","a","b","b","c","c","e","f","c"]
// Scan the array to tally how many times each name appears
var totalDict = [String: Int]()
buttonValues.forEach { totalDict[$0] = (totalDict[$0] ?? 0) + 1 }
// Now scan it again to update names that appear too many times
var runningDict = [String: Int]()
for (index, value) in buttonValues.enumerated() {
let count = runningDict[value] ?? 0
if count >= 2 {
while true {
let newValue = NamePicker()
let newTotal = (totalDict[newValue] ?? 0) + 1
if newTotal < 3 {
buttonValues[index] = newValue
totalDict[newValue] = newTotal
break
}
}
} else {
runningDict[value] = count + 1
}
}
Dictionary is the best way I think. Have the key be the character and the value be the count of that character. Your runtime will be O(n) since you only have to run through each input once. Here is an example:
let chars = ["a","a","a","b","b","c","c","e","f","c"]
var dict = [String: Int]()
for char in chars {
//If already in Dictionary, increase by one
if var count = dict[char] {
count += 1
dict[char] = count
} else {//else is not in the dictionary already, init with 1
dict[char] = 1
}
}
Output:
["b": 2, "e": 1, "a": 3, "f": 1, "c": 3]
Now I'm not sure how you want to replace the value that's the same character for a third time, but this is probably the best way to group the strings to determine which are over the limit.
Instead of inserting the wrong value and then checking if the values are correct, I would suggest to automatically create the correct array.
//array for button names
var buttonValues = Array<String>()
//tracks what value has been inserted how many times
var trackerDict = [String: Int]()
for i in 0...9 {
//we initialize a new variable that tells us if we found a valid value (if the value has not been inserted 2 times already)
var foundValidValue = false
while !foundValidValue{
var val = NamePicker()
//now we check if the value exists and if it is inserted less than 2 times
if let count = trackerDict[val] {
if count < 2 {
foundValidValue = true
}
}
//if we found the value, we can add it
if foundValidValue {
trackerDict[val] = (trackerDict[val] ?? 0) + 1
buttonValues.append(val)
}
//if we did not find it, we just run through the loop again
}
}
I added a dictionary because it is faster to keep track of the count in a dictionary than counting the number of occurrences in the array every time.

How can I perform an Array Slice in Swift?

var mentions = ["#alex", "#jason", "#jessica", "#john"]
I want to limit my array to 3 items, so I want to splice it:
var slice = [String]()
if mentions.count > 3 {
slice = mentions[0...3] //alex, jason, jessica
} else {
slice = mentions
}
However, I'm getting:
Ambiguous subscript with base type '[String]' and index type 'Range'
Apple Swift version 2.2 (swiftlang-703.0.18.8 clang-703.0.31)
Target: x86_64-apple-macosx10.9
The problem is that mentions[0...3] returns an ArraySlice<String>, not an Array<String>. Therefore you could first use the Array(_:) initialiser in order to convert the slice into an array:
let first3Elements : [String] // An Array of up to the first 3 elements.
if mentions.count >= 3 {
first3Elements = Array(mentions[0 ..< 3])
} else {
first3Elements = mentions
}
Or if you want to use an ArraySlice (they are useful for intermediate computations, as they present a 'view' onto the original array, but are not designed for long term storage), you could subscript mentions with the full range of indices in your else:
let slice : ArraySlice<String> // An ArraySlice of up to the first 3 elements
if mentions.count >= 3 {
slice = mentions[0 ..< 3]
} else {
slice = mentions[mentions.indices] // in Swift 4: slice = mentions[...]
}
Although the simplest solution by far would be just to use the prefix(_:) method, which will return an ArraySlice of the first n elements, or a slice of the entire array if n exceeds the array count:
let slice = mentions.prefix(3) // ArraySlice of up to the first 3 elements
We can do like this,
let arr = [10,20,30,40,50]
let slicedArray = arr[1...3]
if you want to convert sliced array to normal array,
let arrayOfInts = Array(slicedArray)
You can try .prefix().
Returns a subsequence, up to the specified maximum length, containing the initial elements of the collection.
If the maximum length exceeds the number of elements in the collection, the result contains all the elements in the collection.
let numbers = [1, 2, 3, 4, 5]
print(numbers.prefix(2)) // Prints "[1, 2]"
print(numbers.prefix(10)) // Prints "[1, 2, 3, 4, 5]"
General solution:
extension Array {
func slice(size: Int) -> [[Element]] {
(0...(count / size)).map{Array(self[($0 * size)..<(Swift.min($0 * size + size, count))])}
}
}
Can also look at dropLast() function:
var mentions:[String] = ["#alex", "#jason", "#jessica", "#john"]
var slice:[String] = mentions
if mentions.count > 3 {
slice = Array(mentions.dropLast(mentions.count - 3))
}
//print(slice) => ["#alex", "#jason", "#jessica"]
I came up with this:
public extension Array {
func slice(count: Int) -> [some Collection] {
let n = self.count / count // quotient
let i = n * count // index
let r = self.count % count // remainder
let slices = (0..<n).map { $0 * count }.map { self[$0 ..< $0 + count] }
return (r > 0) ? slices + [self[i..<i + r]] : slices
}
}
You can also slice like this:
//Generic Method
func slice<T>(arrayList:[T], limit:Int) -> [T]{
return Array(arrayList[..<limit])
}
//How to Use
let firstThreeElements = slice(arrayList: ["#alex", "#jason", "#jessica", "#john"], limit: 3)
Array slice func extension:
extension Array {
func slice(with sliceSize: Int) -> [[Element]] {
guard self.count > 0 else { return [] }
var range = self.count / sliceSize
if self.count.isMultiple(of: sliceSize) {
range -= 1
}
return (0...range).map { Array(self[($0 * sliceSize)..<(Swift.min(($0 + 1) * sliceSize, self.count))]) }
}
}

Resources