Byoth
Byoth

Reputation: 1965

Swift - How to get indexes of filtered items of array

let items: [String] = ["A", "B", "A", "C", "A", "D"]

items.whatFunction("A") // -> [0, 2, 4]
items.whatFunction("B") // -> [1]

Does Swift 3 support a function like whatFunction(_: Element)?

If not, what is the most efficient logic?

Upvotes: 42

Views: 54838

Answers (9)

pacification
pacification

Reputation: 6018

You can achieve this by chain of:

  1. enumerated() - add indexes;
  2. filter() out unnecessary items;
  3. map() our indexes.

Example (works in Swift 3 - Swift 4.x):

let items: [String] = ["A", "B", "A", "C", "A", "D"]  
print(items.enumerated().filter({ $0.element == "A" }).map({ $0.offset })) // -> [0, 2, 4]

Another way is using flatMap, which allows you to check the element and return index if needed in one closure.

Example (works in Swift 3 - Swift 4.0):

print(items.enumerated().flatMap { $0.element == "A" ? $0.offset : nil }) // -> [0, 2, 4]

But since Swift 4.1 flatMap that can return non-nil objects become deprecated and instead you should use compactMap.

Example (works since Swift 4.1):

print(items.enumerated().compactMap { $0.element == "A" ? $0.offset : nil }) // -> [0, 2, 4]

And the cleanest and the most memory-cheap way is to iterate through array indices and check if element of array at current index equals to required element.

Example (works in Swift 3 - Swift 5.x):

print(items.indices.filter({ items[$0] == "A" })) // -> [0, 2, 4]

Upvotes: 33

Brave
Brave

Reputation: 39

this can be a way too

// MARK: - ZIP: Dictionary like

let words = ["One", "Two", "Three", "Four"]
let numbers = 1...words.count

for (word, number) in zip(words, numbers) {
    print("\n\(word): \(number)")
}

Upvotes: 0

Srinivasan_iOS
Srinivasan_iOS

Reputation: 1088

You can use that below code:

var firstArray = ["k","d","r","r","p","k","b","p","k","k"]
var secondArray = ["k","d","r","s","d","r","b","c"]

let filterArray = firstArray.filter { secondArray.contains($0) }
let filterArray1 = firstArray.filter { !secondArray.contains($0) }
let filterIndex = firstArray.enumerated().filter { $0.element == "k" }.map { $0.offset }
print(filterArray) --> // ["k", "d", "r", "r", "k", "b", "k", "k"]
print(filterArray1) --> // ["p", "p"]
print(filterIndex) --> // [0, 5, 8, 9]

Upvotes: 1

Julien Kode
Julien Kode

Reputation: 5499

In Swift 3 and Swift 4 you can do that:

let items: [String] = ["A", "B", "A", "C", "A", "D"]

extension Array where Element: Equatable {

    func indexes(of item: Element) -> [Int]  {
        return enumerated().compactMap { $0.element == item ? $0.offset : nil }
    }
}

items.indexes(of: "A")

I hope my answer was helpful 😊

Upvotes: 9

vadian
vadian

Reputation: 285270

You can filter the indices of the array directly, it avoids the extra mapping.

let items = ["A", "B", "A", "C", "A", "D"]
let filteredIndices = items.indices.filter {items[$0] == "A"}

or as Array extension:

extension Array where Element: Equatable {

    func whatFunction(_ value :  Element) -> [Int] {
        return self.indices.filter {self[$0] == value}
    }

}

items.whatFunction("A") // -> [0, 2, 4]
items.whatFunction("B") // -> [1]

or still more generic

extension Collection where Element: Equatable {

    func whatFunction(_ value :  Element) -> [Index] {
        return self.indices.filter {self[$0] == value}
    }

}

Upvotes: 51

bretcj7
bretcj7

Reputation: 355

For example finding the indices of p_last values that are in inds1 array: (swift 4+)

let p_last = [51,42]
let inds1 = [1,3,51,42,4]
let idx1 = Array(inds1.filter{ p_last.contains($0) }.indices)

idx1 = [0,1]

Upvotes: -1

sejal thesiya
sejal thesiya

Reputation: 64

just copy and paste

extension Array {
  func whatFunction(_ ids :  String) -> [Int] {

    var mutableArr = [Int]()
    for i in 0..<self.count {
        if ((self[i] as! String) == ids) {
            mutableArr.append(i)
        }
    }
        return mutableArr 
  }

}

Upvotes: 1

Abdelahad Darwish
Abdelahad Darwish

Reputation: 6067

you can use it like that :

 let items: [String] = ["A", "B", "A", "C", "A", "D"]

        let indexes = items.enumerated().filter {
            $0.element == "A"
            }.map{$0.offset}

        print(indexes)

Upvotes: 4

Yannick
Yannick

Reputation: 3278

You can create your own extension for arrays.

extension Array where Element: Equatable {
    func indexes(of element: Element) -> [Int] {
        return self.enumerated().filter({ element == $0.element }).map({ $0.offset })
    }
}

You can simply call it like this

items.indexes(of: "A") // [0, 2, 4]
items.indexes(of: "B") // [1]

Upvotes: 36

Related Questions