简体   繁体   English

打破filter()函数

[英]break out of filter() function

I'd like to optimize my functions which rely on filter(). 我想优化依赖filter()的函数。 In some cases I want to break out of them when they reach a certain elements. 在某些情况下,我想在达到某些元素时突破它们。 (For example, I may have an array of distinct elements. Or, I just want to implement a kind of findFirst functionality.) In such instances it seems inefficient for the function to continue until the end of the array. (例如,我可能有一个不同元素的数组。或者,我只想实现一种findFirst功能。)在这种情况下,函数继续直到数组结束似乎效率低下。

This is something very easy with loops, but I would like to apply the optimisations to functional programming principals. 这对于循环非常简单,但我想将优化应用于函数式编程主体。 (The compiler wouldn't be able to perform such a optimization by itself, since it doesn't know my array and my intention.) (编译器本身无法执行这样的优化,因为它不知道我的数组和我的意图。)

Can this be done? 可以这样做吗?

There is first(where:) that breaks out when it finds the first passing case: first(where:)在找到第一个传递案例时爆发:

let data = ["Alpha","Beta","Gamma","Delta"]

let b2 = data.first(where:{$0=="Beta"})

filter isn't written to break out like that. filter不会像那样被打破。 I don't believe there's an out-of-the-box way to do the kind of thing you're looking for. 我不相信有一种开箱即用的方式来做你正在寻找的那种东西。

Generally it's better to avoid making functions more flexible to cover narrow cases. 一般来说,最好避免使功能更灵活,以涵盖狭窄的情况。 Adding early bail might be useful sometimes but would come at the cost of complicating filter , and the code would probably be hard to read (bear in mind one of the main goals of using functions like filter , map etc is to make the code easier to read and to be certain the code is correct). 添加早期保释有时可能会有用,但会以复杂的filter为代价,并且代码可能难以阅读(请记住使用filtermap等功能的主要目标之一是使代码更容易阅读并确定代码是正确的)。 Some functions do support early exit though, when it's fundamental to their purpose - for example, contains or indexOf . 有些函数确实支持提前退出,当它是其目的的基础时 - 例如, containsindexOf

But it's not too hard to create your own higher-order functions to do what you want, the name of which makes their intent pretty clear. 但是创建你自己的高阶函数来做你想要的并不是很难,其名称使他们的意图非常明确。 For example, to take all the elements in a sequence up to the first one that doesn't match a pattern, you could write takeWhile like this: 例如,要将序列中的所有元素都带到与模式不匹配的第一个元素中,您可以像这样编写takeWhile

extension SequenceType {
    func takeWhile(condition: Generator.Element -> Bool) -> [Generator.Element] {
        var result: [Generator.Element] = []
        for x in self {
            guard condition(x) else { break }
            result.append(x)
        }
        return result
    }
}



let nums = [1,3,1,2]
let isOdd = { $0%2 == 1 }
let initialOdd = nums.takeWhile(isOdd)
print(initialOdd)

The point of using filter is to factor out the predicate and scan the whole collection. 使用过滤器的关键是分解出谓词并扫描整个集合。 You can't find out which data to filter till you went thru the whole data set. 在通过整个数据集之前,您无法找出要过滤的数据。 In its basic form filter is just a check on the a condition (predicate) to construct a new collection: 在其基本形式过滤器只是检查构建新集合的条件(谓词):

let bools = [true, false, false, true]

print(bools.filter {$0})

What you are asking is gaining control of the iterator loop in filter while filter is implemented to simplify it by hiding it. 您要问的是获得对过滤器中迭代器循环的控制,同时实现过滤器以通过隐藏它来简化它。 I suggest you use the control flow statements built in the language (if, for, etc, continue, break) to give you what you need. 我建议你使用语言中构建的控制流语句(if,for,etc,continue,break)来提供你需要的东西。 No point forcing weird syntax statements that make your code looks more convoluted and ungrokable. 没有必要强迫奇怪的语法语句使你的代码看起来更复杂和不可思议。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM