【问题标题】:Complicated filtering involving array and object with array member涉及数组和具有数组成员的对象的复杂过滤
【发布时间】:2018-05-23 18:54:43
【问题描述】:

我有两个数组

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

Thing 有自己的内容,像这样

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

我想做类似下面的事情,我会得到一个 Thing 类型的数组,其元素的内容不与另一个数组 badContents 重叠

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

因此,我会得到这样的结果

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"
}

【问题讨论】:

  • @JoshCaswell 谢谢,但这实际上不是我想做的。主要区别在于我试图获得类型为 [Thing] 的结果,该类型的 member 属性 与另一个数组相当。如果我的badContents 的类型为[Thing],则链接的问题可能会起作用
  • @rdk:在您的过滤方法中,您要检查 "thing.contents 和 badContents 是否不共享任何元素" - 换句话说,如果这两个数组没有共同的元素。因此,上面的链接应该有助于找到解决方案。
  • @MartinR 谢谢!我现在知道如何在我的解决方案中使用它!
  • 请将您的解决方案作为答案发布,并将其标记为已接受。附: arrayOfCommonElements 是一个非常糟糕的 O(N^2) 解决方案

标签: arrays swift filter filtering


【解决方案1】:
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
}

【讨论】:

    【解决方案2】:

    它可能对性能没有太大影响(除非badThings 很大,或者contents 很大并且“坏事”很常见),但我可能仍然会这样做,而不是不需要任何新的扩展:

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

    即使您保持接近,当您发现碰撞时,我也会停止搜索。找到所有的冲突然后检查.count == 0 只是有点浪费,而且不是特别容易阅读。

    另外,虽然在时间和空间上效率稍低,但以下 IMO 非常明确:

    let badContents = Set(["b1", "b2"])
    
    func filteredThings2() -> [Thing] {
        return things.filter { Set($0.contents).intersection(badContents).isEmpty }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-11-05
      • 2021-12-12
      • 2016-02-02
      • 2019-11-20
      • 2011-01-26
      • 2019-08-20
      • 2016-02-14
      • 1970-01-01
      相关资源
      最近更新 更多