0

I have an array of custom objects, having ID values as properties. Now I have another array of selected objects (selected by IDs). How can I get the indices of the first array by filtering for the selected IDs (second array)?

I would like to avoid looping and think of a solution using compactMap or similar.

struct MyObject {
    var ID: Int
    var name: String
}

let myObjects = [
    MyObject(ID: 3, name: "AAAA"),
    MyObject(ID: 5, name: "BBBB"),
    MyObject(ID: 12, name: "CCCC"),
    MyObject(ID: 15, name: "DDDD"),
    MyObject(ID: 20, name: "EEEE"),
    MyObject(ID: 21, name: "GGGG"),
    MyObject(ID: 22, name: "HHHH"),
    MyObject(ID: 23, name: "IIII"),
]
let selectedIds = [5, 20, 23]

// How to get an array of indices for selectedIds
// Expected result [1, 4, 7]
Pauli
  • 343
  • 1
  • 4
  • 17

2 Answers2

2
myObjects.enumerated()   // Pair-up elements and their offsets
    .filter { selectedIds.contains($0.element.ID) }  // Get the ones you want
    .map { $0.offset }  // Extract the offsets
Rob Napier
  • 286,113
  • 34
  • 456
  • 610
  • Is this faster or slower than the answer from @vadian `myObjects.indices.filter{selectedIds.contains(myObjects[$0].ID)}` – Pauli Feb 05 '20 at 19:17
  • If it matters in your specific case, then benchmark your specific case. Benchmarking this is very tricky to do correctly, and small differences in your situation can change the performance significantly. If such a small micro-optimization is important to your situation, there are more performant ways to do this, at the cost of code complexity, and the cost of retesting the performance every time the compiler is changed. – Rob Napier Feb 05 '20 at 19:57
  • @Pauli The advantage of vadian's approach is that it would work on collection slices as well. A enumeration offset it is not the same as a collection index – Leo Dabus Feb 05 '20 at 19:59
  • That is correct; you'd have to replace this with `zip(myObjects.indices, myObjects)` to get the same index-based behavior across non-arrays. Vadian's approach also would work for arbitrary collections, which is nice. – Rob Napier Feb 05 '20 at 20:00
  • @RobNapier thanks for giving the additional details. I will accept vadian's approach as it seems to be a bit more complete, but upvote yours as it works fine. Thank you – Pauli Feb 05 '20 at 20:33
  • @RobNapier related https://stackoverflow.com/a/54877538/2303865 enumeratedIndices – Leo Dabus Feb 05 '20 at 22:27
1

You could filter the indices

let selectedIndices = myObjects.indices.filter{selectedIds.contains(myObjects[$0].ID)}
vadian
  • 274,689
  • 30
  • 353
  • 361