Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
2.0k views
in Technique[技术] by (71.8m points)

arrays - What is the difference between filter(_:).first and first(where:)?

Please consider the following strings array:

let strings = ["str1", "str2", "str10", "str20"]

Let's assume that what required is to get the first element (String) which contains 5 characters, I could get it by using filter(_:) as follows:

let filterString = strings.filter { $0.count == 5 }.first
print(filterString!) // str10

but after reviewing the first(where:) method, I recognized that I will be able to get the same output:

let firstWhereString = strings.first(where: { $0.count == 5 })
print(firstWhereString!) // str10

So what is the benefit of using one instead of the other? is it only about that the filter(_:) returns a sequence and the first(where:) returns a single element?

Update:

I noticed that the filter(_:) took 5 times to do such a process, while first(where:) took 4 times:

enter image description here

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

You are correct in observing that filter(_:) returns all elements that satisfy a predicate and that first(where:) returns the first element that satisfy a predicate.

So, that leaves us with the more interesting question of what the difference is between elements.filter(predicate).first and elements.first(where: predicate).

As you've already noticed they both end up with the same result. The difference is in their "evaluation strategy". Calling:

elements.filter(predicate).first

will "eagerly" check the predicate against all elements to filter the full list of elements, and then pick the first element from the filterer list. By comparison, calling:

elements.first(where: predicate)

will "lazily" check the predicate against the elements until it finds one that satisfies the predicate, and then return that element.

As a third alternative, you can explicitly use "a view onto [the list] that provides lazy implementations of normally eager operations, such as map and filter":

elements.lazy.filter(predicate).first

This changes the evaluation strategy to be "lazy". In fact, it's so lazy that just calling elements.lazy.filter(predicate) won't check the predicate against any elements. Only when the first element is "eagerly" evaluated on this lazy view will it evaluate enough elements to return one result.


Separately from any technical differences between these alternatives, I'd say that you should use the one that most clearly describes your intentions. If you're looking for the first element that matches a criteria/predicate then first(where:) communicates that intent best.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...