【问题标题】:Filter Swift Array and Give Indices (Not Values)过滤 Swift 数组并给出索引(不是值)
【发布时间】:2018-03-01 15:12:09
【问题描述】:

我需要根据元素的某些条件过滤数组,但我需要获取通过测试的元素的索引而不是元素本身。

例如:给定一个Bool 数组,我想将其转换为一个Int 数组,其中仅包含原始数组中true 元素的索引。

可以这样做:

// INPUT array:
let flags = [true, false, true, false]

// OUTPUT array:
var trueIndices = [Int]()

for (index, value) in flags.enumerated() where value == true {
    trueIndices.append(index)
}

...但它根本不是“快速”

有没有更优雅的方式?类似于filter(),但返回的是索引而不是元素。

【问题讨论】:

  • 非常感谢大家。你所有答案中的 “迅速” 太高了

标签: arrays swift functional-programming


【解决方案1】:

您可以直接filter索引

let flags = [true, false, true, false]    
let trueIndices = flags.indices.filter{ flags[$0] }

let falseIndices = flags.indices.filter{ !flags[$0] }

【讨论】:

  • 哦,现在说得通了。您正在使用捕获外部 flags 数组的闭包过滤所有索引的数组 (?),并在当前索引 ($0) 处测试其内容。
  • 这是“更快捷”
  • “在门户中思考”还有很长的路要走!
  • 当然可以为集合定义一个func indices(where isIncluded: (Element) -> Bool) -> [Index] 扩展方法...
  • 提醒一下:这仅在可以下标时才有效,并且可以在O(1) 中使用。不适用于序列
【解决方案2】:

不确定 "swiftier" 是多少,但您也可以使用连续的 filtermap 操作,或者只使用一个 flatMap。当然,您可以将数组声明为不可变,而不必编写任何显式循环,这两种方法通常都被认为比您当前的方法更实用。

let trueIndices = flags.enumerated().filter{$0.element}.map{$0.offset}
print(trueIndices)

输出:

[0,2]

使用单个flatMap

let trueIndices = flags.enumerated().flatMap { (offset, flag) in flag ? offset : nil }

【讨论】:

  • 当然! enumerated() 给出了一个元组数组,我可以过滤/映射 那个。猜猜我现在已经编码太多小时了......
  • flatMap 版本无法在 Xcode 9 中编译。我的建议:flags.enumerated().flatMap { (offset, flag) in flag ? offset : nil }
  • @MartinR 感谢您的提示,我只在 Xcode 8 中测试过,但更新了我的答案,因为无论如何您的解决方案更清晰
  • 你的意思可能是"声明数组immutable"
  • 是的,我正在编辑我的措辞,忘记将 mutable 更改为 immutable,谢谢。
【解决方案3】:

这就是我要做的。它可以推广到序列,甚至是下标不是 O(1) 的集合。

let indicesOfTrue = Array(flags.enumerated().lazy.filter{ $0.element }.map{ $0.offset })

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-09-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多