1

I have two arrays

let badContents = ["b1", "b2"]
let things: [Thing] = ...

where a Thing has its own contents, like this

print(things[0].contents)
// ["g1", "b1", "b2"]

I wanted to do something like the below, where I would get an array of type Thing whose elements had contents that did not overlap with another array, badContents

func filteredThings() -> [Thing] {
    return things.filter({ (thing) -> Bool in {
        return // thing.contents and badContents do not share any elements
    }()
    })
}

Thus, I would get a result like this

let things = [Thing(name: "1", contents: ["g1", "b2"), Thing(name: "2", contents: ["g1", "g2"])]

let goodThings = filteredThings() // removes Thing named "1" because its contents contain "b2"

for goodThing in goodThings {
    print(goodThing.name)
    // "2"
}
5
  • 2
    How to get list of common elements of 2 arrays in Swift? Commented Dec 9, 2017 at 20:33
  • @JoshCaswell Thanks but thats not actually what I want to do. The main difference is that I am trying to get a result of type [Thing] who has a member property that is comparable to the other array. The linked question would work maybe if my badContents was of type [Thing] Commented Dec 9, 2017 at 20:43
  • 4
    @rdk: In your filter method you want to check if "thing.contents and badContents do not share any elements" – in other words, if these 2 arrays have no common elements. Therefore the above link should help to find a solution. Commented Dec 9, 2017 at 20:57
  • @MartinR Thanks! I now see how to use that in my solution! Commented Dec 9, 2017 at 21:32
  • Please post your solution as an answer, and mark it as accepted. P.S. that arrayOfCommonElements is a really crappy O(N^2) solution Commented Dec 9, 2017 at 23:31

2 Answers 2

1

It probably doesn't make much difference for performance (unless badThings is large, or contents is both large and "bad things" are common), but I'd probably still do it this way instead, which doesn't require any new extensions:

let badContents = Set(["b1", "b2"])

func filteredThings() -> [Thing] {
    return things.filter { $0.contents.first(where: { badContents.contains($0) }) == nil }
}

Even if you keep your approach, I'd stop searching when you found a collision. Finding all the collisions and then checking .count == 0 is just kind of wasteful without being particularly easier to read.

Alternately, while a little less efficient in time and space, the following IMO is extremely explicit:

let badContents = Set(["b1", "b2"])

func filteredThings2() -> [Thing] {
    return things.filter { Set($0.contents).intersection(badContents).isEmpty }
}
Sign up to request clarification or add additional context in comments.

Comments

0
func filteredThings() -> [Thing] {
    return things.filter({ (thing) -> Bool in {
        return arrayOfCommonElements(lhs: thing.contents, rhs: badContents).count == 0
    }()
    })
}
func arrayOfCommonElements <T, U> (lhs: T, rhs: U) -> [T.Iterator.Element] where T: Sequence, U: Sequence, T.Iterator.Element: Equatable, T.Iterator.Element == U.Iterator.Element {
    var returnArray:[T.Iterator.Element] = []
    for lhsItem in lhs {
        for rhsItem in rhs {
            if lhsItem == rhsItem {
                returnArray.append(lhsItem)
            }
        }
    }
    return returnArray
}

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.