Reputation: 698
Here is a group array.
var group = ["H","H","E","D",
"G","D","G","E",
"D","B","A","B",
"A","A","G","C",
"C","H","D","G",
"H","B","E","F",
"F","C","E","A",
"B","C","F","F"]
I want to do something like this to find indices of "A".
group.index(of: "A"!)
But this will return only first index, but not other indices for next three "A"s.
print(group.index(of: "A")!) //10
What do I do to get the program to return all four indices for "A"?
Upvotes: 7
Views: 4101
Reputation: 236370
You can extend collection and create your own indices method that takes a predicate.
extension Collection where Element: Equatable {
func indices(where predicate: @escaping (Element) throws -> Bool) rethrows -> [Index] {
try self.indices.filter({try predicate(self[$0])})
}
func indices(of element: Element) -> [Index] {
self.indices.filter({self[$0] == element})
}
}
For collections indexed by Int you can return an IndexSet:
extension Collection where Element: Equatable, Index == Int {
func indexSet(where predicate: @escaping (Element) throws -> Bool) rethrows -> IndexSet {
.init(try indices(where: predicate))
}
func indexSet(of element: Element) -> [Index] {
.init(indices(of: element))
}
}
Usage:
let array = [10, 20, 30, 5, 15, 25, 50]
let indices = array.indices { $0.isMultiple(of: 3) }
for index in indices {
print("element:", array[index], "at:", index)
}
This will print
element: 30 at: 2
element: 15 at: 4
let group = ["H","H","E","D","G","D","G","E","D","B","A","B","A","A","G","C","C","H","D","G","H","B","E","F","F","C","E","A","B","C","F","F"]
let indices = group.indices(of: "A")
print(indices)
This will print
[10, 12, 13, 27]
Upvotes: 0
Reputation: 698
After reading about Extensions
and functional programming past few days, I wanted to try writing an extension function for Array
class. Here it is:
var group = ["H","H","E","D",
"G","D","G","E",
"D","B","A","B",
"A","A","G","C",
"C","H","D","G",
"H","B","E","F",
"F","C","E","A",
"B","C","F","F"]
var group2 = [1,2,3,4,5,6,7,8]
// Create a nice Array extension method that will return indices of wanted group.
extension Array where Element: Equatable {
func showIndices(indexOf groupName: Element) -> [Int] {
return self.enumerated().compactMap {
$0.element == groupName ? $0.offset : nil
}
}
}
group.showIndices(indexOf: "A")
group2.showIndices(indexOf: 1)
// [10, 12, 13, 27]
// [0]
Upvotes: 0
Reputation: 10105
You might use a combination of enumerated
and compactMap
:
let indexArray = group.enumerated().compactMap {
$0.element == "A" ? $0.offset : nil
}
print(indexArray) // [10, 12, 13, 27]
Upvotes: 13
Reputation: 32809
A reduce
, generic, based solution:
let group = ["H","H","E","D",
"G","D","G","E",
"D","B","A","B",
"A","A","G","C",
"C","H","D","G",
"H","B","E","F",
"F","C","E","A",
"B","C","F","F"]
extension Array where Element: Equatable {
func indexes(of element: Element) -> [Index] {
return enumerated().reduce([]) { $1.element == element ? $0 + [$1.offset] : $0 }
}
}
group.indexes(of: "A") // 10, 12, 13, 27]
Another approach would be to built-up a letter-to-indices dictionary and query that:
let indices = Dictionary(group.enumerated().map { ($1, [$0]) }, uniquingKeysWith: +)
indices["A"] ?? [] // [10, 12, 13, 27]
, though for this solution you'd need to unwrap the result as the dictionary subscript returns an optional value.
BTW, your array could've been a let
instead of a var
, constants bring predictability over your code, I recommend using them as much as possible.
Upvotes: 1
Reputation: 20244
Vadian's answer above is already the most concise yet.
The rest of the answers just dance about chained HUFs because it's cool but just for true completeness, as the most basic implementation one would obviously do the following:
let group = ["H","H","E","D",
"G","D","G","E",
"D","B","A","B",
"A","A","G","C",
"C","H","D","G",
"H","B","E","F",
"F","C","E","A",
"B","C","F","F"]
var array = [Int]()
for index in 0..<group.count {
if group[index] == "A" {
array.append(index)
}
}
Upvotes: 1
Reputation: 285072
For the sake of completeness this is another different approach which filter
s the indices
let group = ["H","H","E","D",
"G","D","G","E",
"D","B","A","B",
"A","A","G","C",
"C","H","D","G",
"H","B","E","F",
"F","C","E","A",
"B","C","F","F"]
let indices = group.indices.filter{ group[$0] == "A"}
Upvotes: 2
Reputation: 42143
Or just enumerate/filter/map :
group.enumerated().filter{$1=="A"}.map{$0.offset}
[EDIT] Changed $0.0 to $0.offset as per Alexander's recommendation (makes the code more legible/explicit)
Upvotes: 8
Reputation: 20804
You can use a simple cycle
Use this Code
var group = ["H","H","E","D",
"G","D","G","E",
"D","B","A","B",
"A","A","G","C",
"C","H","D","G",
"H","B","E","F",
"F","C","E","A",
"B","C","F","F"]
var indexes : [Int] = []
for (index,string) in group.enumerated() {
if(string == "A") {
indexes.append(index)
}
}
debugPrint(indexes)
Upvotes: 4