0

I am trying to create a filtering system for some items by checking if the selected items exist in the presented values.

So my selectable array can range from 0 to 6, and each item contains an array of Ints that it is associated with:

let items = [
 Item(cat: [1, 2, 3]),
 Item(cat: [0, 6]),
 Item(cat: []),
 Item(cat: [0, 1])
]

I wanted to create a function that would check if any of the cat values were in the selected Ints:

@Published var filteredCats: [Int] = []

func filterByInt(array: [Item]) -> [Item] {
 let output = array.filter({
  guard let cats = $0.cats else { return true }

  for cat in cats {
   return filteredCats.contains(cat)
  }
 })
 return output
}

But I'm having issue with the above since it returns in the loop on the first iteration, so if I was searching for 1 in the above items then Item(cat: [0, 1]) exits at false as the first looped check is 0==1.

Essentially I want to be able to do the following (in expanded terms):

let filter = [0, 3, 4]
let items = [
 [1, 2, 3],
 [2, 3],
 [],
 [5, 6, 7]
]

items.contains(filter) // --> return the arrays

Sorry if this is basic but I've been trying to find a good solution.

2 Answers 2

2

Checking uniqueness is where a Set can help

struct Item {
    var cat: Set<Int>
}

let items = [
 Item(cat: [1, 2, 3]),
 Item(cat: [0, 6]),
 Item(cat: []),
 Item(cat: [0, 1])
]

let wanted: Set<Int> = [0, 3, 4]

let filtered = items.filter { !$0.cat.isDisjoint(with: wanted) }
Sign up to request clarification or add additional context in comments.

1 Comment

And another reason to prefer set as a better data structure here, for a selection of numbers 0-6, because it means you can't represent e.g. [1, 2, 3, 1, 1, 2, 3, 2] and that makes invalid state impossible to represent, and that eliminates bugs
1

I'd suggest someSatisfy (or any in Kotlin):

We can utilize allSatisfy with double negations (one for allSatisfy, the other for contains) for that:

struct Item: CustomDebugStringConvertible {
    let cat: [Int]
    
    var debugDescription: String {
        "[" + cat.map { String($0) }.joined(separator: ", ") + "]"
    }
}

func filterByInt(items: [Item], filter: [Int]) -> [Item] {
    // Early return might make sense if the filter is empty.
    // guard !filter.isEmpty else { return items }
    
    items.filter { item in
        !filter.allSatisfy {
            filterItem in !item.cat.contains(filterItem)
        }
    }
}

let filter = [0, 3, 4]
let items: [Item] = [
    .init(cat: [1, 2, 3]),
    .init(cat: [2, 3]),
    .init(cat: []),
    .init(cat: [5, 6, 7])
]

print(filterByInt(items: items, filter: filter))
// [[1, 2, 3], [2, 3]]

print(filterByInt(items: items, filter: [5]))
// [[5, 6, 7]]

print(filterByInt(items: items, filter: []))
// []

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.