how to count specific items in array in swift - arrays

Let's say i have array of any object below , I'm looking for a way to count items in the array as following:
var OSes = ["iOS", "Android", "Android","Android","Windows Phone", 25]
Is there a short way for swift to do something like this below ?
Oses.count["Android"] // 3

A fast, compact and elegant way to do it is by using the reduce method:
let count = OSes.reduce(0) { $1 == "Android" ? $0 + 1 : $0 }
It's more compact than a for loop, and faster than a filter, because it doesn't generate a new array.
The reduce method takes an initial value, 0 in our case, and a closure, applied to each element of the array.
The closure takes 2 parameters:
the value at the previous iteration (or the initial value, 0 in our case)
the array element for the current iteration
The value returned by the closure is used as the first parameter in the next iteration, or as the return value of the reduce method when the last element has been processed
The closure simply checks if the current element is Android:
if not, it returns the aggregate value (the first parameter passed to the closure)
if yes, it returns that number plus one

It's pretty simple with .filter:
OSes.filter({$0 == "Android"}).count // 3

Swift 5 with count(where:)
let countOfAndroid = OSes.count(where: { $0 == "Android" })
Swift 4 or less with filter(_:)
let countOfAndroid = OSes.filter({ $0 == "Android" }).count

Related

Swift: Capture list

var array = [() -> ()]()
var count = 0
var index = 0
while index < 5 {
array.append {
print("count: \(count)")
print("index: \(index)")
}
count += 1
index += 1
}
array[0]()
array[4]()
Output:
count: 5
index: 5
count: 5
index: 5
Same case but with some changes:
var array = [() -> ()]()
var count = 0
for index in 0..<5 {
array.append {
print("count: \(count)")
print("index: \(index)")
}
count += 1
}
array[0]()
array[4]()
Output:
count: 5
index: 0
count: 5
index: 4
Count value would be the same in both the cases as we are not explicitly capturing it, i.e 5
In the first case global index variable is used and the result is the last incremented value i.e. 5 and 5
In the second case for loop's index is used and the value is 0 and 4 respectively.
What is the exact difference?
In the first example index is var declared and it is the same variable used each time, in the second it is let declared so in the second example it is a new instance of index that exists in the scope of the for loop for each iteration
I Debugged that code because it looked kinda weird but just let me tell you, the appending and increment line goes well, When you call array0 and array4, the debugger goes to the body of append{} and print those variables. and captures those variable from most easily accessible scope. so in first case, it will capture from the scope of function body which values are actually new 5 and 5 for both count and index.
in second case, it will try to capture if there is a variable count and index initialized, it will find count but wont find so it will check inside the body of array and there it will find the actual value which is 0 in first index and 4 in 5th index.
That's all i can explain, Sorry for bad english
Check Debugger Image Here

How can I find if the index number for a specific item in an array also exists as an integer in the same array?

I'm trying to find the index value of the word "odd", then return true if that index value also exists an integer within the same array.
E.g.
array = ["even",9,"even",88,"even",777,"even",10,"odd",8,"even"]
The index of "odd" here is [8].
When I store the index value as a variable named odd, then use .include? to see if it is in the array above, my function returns false.
Since the number 8 exists in array and the value of odd is also 8, why does my function return false?
def does_the_index_of_odd_exist(x)
odd = x.each_index.select { |i| x[i] == "odd" }
x.include?(odd)
end
Any help explaining this is greatly appreciated. I've just started learning!
If I understand the point, you should be able to use just:
array.include? array.index "odd"
x.each_index.select { |i| x[i] == "odd" }
=> [8] #array
but not "odd"
so use find instead of select, it returns string element in array

Why and when to use lazy with Array in Swift?

[1, 2, 3, -1, -2].filter({ $0 > 0 }).count // => 3
[1, 2, 3, -1, -2].lazy.filter({ $0 > 0 }).count // => 3
What is the advantage of adding lazy to the second statement. As per my understanding, when lazy variable is used, memory is initialized to that variable at the time when it used. How does it make sense in this context?
Trying to understand the the use of LazySequence in little more detail. I had used the map, reduce and filter functions on sequences, but never on lazy sequence. Need to understand why to use this?
lazy changes the way the array is processed. When lazy is not used, filter processes the entire array and stores the results into a new array. When lazy is used, the values in the sequence or collection are produced on demand from the downstream functions. The values are not stored in an array; they are just produced when needed.
Consider this modified example in which I've used reduce instead of count so that we can print out what is happening:
Not using lazy:
In this case, all items will be filtered first before anything is counted.
[1, 2, 3, -1, -2].filter({ print("filtered one"); return $0 > 0 })
.reduce(0) { (total, elem) -> Int in print("counted one"); return total + 1 }
filtered one
filtered one
filtered one
filtered one
filtered one
counted one
counted one
counted one
Using lazy:
In this case, reduce is asking for an item to count, and filter will work until it finds one, then reduce will ask for another and filter will work until it finds another.
[1, 2, 3, -1, -2].lazy.filter({ print("filtered one"); return $0 > 0 })
.reduce(0) { (total, elem) -> Int in print("counted one"); return total + 1 }
filtered one
counted one
filtered one
counted one
filtered one
counted one
filtered one
filtered one
When to use lazy:
option-clicking on lazy gives this explanation:
From the Discussion for lazy:
Use the lazy property when chaining operations:
to prevent intermediate operations from allocating storage
or
when you only need a part of the final collection to avoid unnecessary computation
I would add a third:
when you want the downstream processes to get started sooner and not have to wait for the upstream processes to do all of their work first
So, for example, you'd want to use lazy before filter if you were searching for the first positive Int, because the search would stop as soon as you found one and it would save filter from having to filter the whole array and it would save having to allocate space for the filtered array.
For the 3rd point, imagine you have a program that is displaying prime numbers in the range 1...10_000_000 using filter on that range. You would rather show the primes as you found them than having to wait to compute them all before showing anything.
I hadn't seen this before so I did some searching and found it.
The syntax you post creates a lazy collection. A lazy collection avoids creating a whole series of intermediate arrays for each step of your code. It isn't that relevant when you only have a filter statement it would have much more effect if you did something like filter.map.map.filter.map, since without the lazy collection a new array is created at each step.
See this article for more information:
https://medium.com/developermind/lightning-read-1-lazy-collections-in-swift-fa997564c1a3
EDIT:
I did some benchmarking, and a series of higher-order functions like maps and filters is actually a little slower on a lazy collection than on a "regular" collection.
It looks like lazy collections give you a smaller memory footprint at the cost of slightly slower performance.
Edit #2:
#discardableResult func timeTest() -> Double {
let start = Date()
let array = 1...1000000
let random = array
.map { (value) -> UInt32 in
let random = arc4random_uniform(100)
//print("Mapping", value, "to random val \(random)")
return random
}
let result = random.lazy //Remove the .lazy here to compare
.filter {
let result = $0 % 100 == 0
//print(" Testing \($0) < 50", result)
return result
}
.map { (val: UInt32) -> NSNumber in
//print(" Mapping", val, "to NSNumber")
return NSNumber(value: val)
}
.compactMap { (number) -> String? in
//print(" Mapping", number, "to String")
return formatter.string(from: number)
}
.sorted { (lhv, rhv) -> Bool in
//print(" Sorting strings")
return (lhv.compare(rhv, options: .numeric) == .orderedAscending)
}
let elapsed = Date().timeIntervalSince(start)
print("Completed in", String(format: "%0.3f", elapsed), "seconds. count = \(result.count)")
return elapsed
}
In the code above, if you change the line
let result = random.lazy //Remove the .lazy here to compare
to
let result = random //Removes the .lazy here
Then it runs faster. With lazy, my benchmark has it take about 1.5 times longer with the .lazy collection compared to a straight array.

Get the base array of an enumerated array

I need to sort an array based on the value as well as the index of each element, so I'd like to do something like this:
let a = [4,9,5,7].enumerate()
let b = a.sort { ... }
But then I need to convert b back to an array without the indices. My current solution is
let c = b.map { $0.1 }
But I was wondering, if there's a simpler way, since b is of the type EnumerateSequence<Array<Int>> and has a property base which holds the array that I want. Unfortunately base is internal and I don't know if there is any method that returns what I want.
Note: You might have noticed that this is Swift 2. While I need a solution in Swift 2 (if there is any), I am of course interested if there's a difference between Swift 2 and Swift 3.
But I was wondering, if there's a simpler way
No. let c = b.map { $0.1 } is simple.
This is slightly (2 characters) simpler:
let c = b.map { $1 }
map receives a tuple of two values, so you can either refer to the two values as $0.0 and $0.1, or as $0, and $1. When your closure uses only $0, then $0 is the entire tuple, so .0 and .1 refers to the individual items. When your closure mentions $1, then $0 is the first item of the tuple and $1 is the second item of the tuple.

How do I check if an element occurs more than twice in an array, subject to a string pattern?

I'm using Ruby 2.4. I know how to check if an eleemnt has never occurred more than twice in an array, using
data_arr.count(string) <= 2
but what if my array is
["1/5", "2/6", "3/5", "4/7", "3/8", "3/9"]
how do I check that the first number before the "/" never occurs more than twice when it is found before the "/"? That is, in the above example, "1" never occurs more than twice (only in the element "1/5") but "3" occurrs 3 times before the "/".
2.2.1 :005 > array = ["1/5", "2/6", "3/5", "4/7", "3/8", "3/9"]
=> ["1/5", "2/6", "3/5", "4/7", "3/8", "3/9"]
2.2.1 :006 > array.count{|m| m.match(/3\//) }
=> 3
This works by "passing a block" to the count method. The block is evaluated for each item m and if true, the item is 'counted.'
In this case I'm using a regular expression to select items with '3' before the slash.
re: comments, you can interpolate any number you'd like into the regex/string/whatever as follows:
regex: /#{variable}/
string: "#{string}"
You might begin by using hash::new with a default value of zero to construct a counting hash.
arr = ["1/5", "2/6", "3/5", "4/7", "3/8", "3/9"]
h = arr.each_with_object(Hash.new(0)) { |s,h| h[s[/\d+(?=\/)/]] += 1 }
#> {"1"=>1, "2"=>1, "3"=>3, "4"=>1}
Then write
h.any? { |_,v| v > 2 }
#=> true
The first step I would suggest is to do a string-split on each string of your array. That way, you could check for recurrences among the integers.
For example, for each element in your array, do
array[element].split("") and go from there.
If you want to check if ANY numerator* has occurred more than twice in the array you use this code:
data_arr.each do |element|
numerator = element.match(/(.+)\//)
if data_arr.count {|e| e.match(/^#{numerator}\//)} > 2
# do something if the element matches more than twice
end
end
* numerator is the number before the / in division.

Resources