什么是最(性能)高效且可读的“拆分”方式?基于条件的通用列表?
(高度简化的示例) 我有一个通用的字符串列表:
var strings = new List<string> { "abc", "owla", "paula", "lala", "hop" };
我正在寻找最有效的方法来将此列表拆分为包含满足条件的元素的列表和不满足相同条件的元素的列表。
Func<string, bool> condition = s => s.IndexOf("o") > -1;
Predicate<string> kickOut = s => s.IndexOf("o") > -1;
var stringsThatMeetCondition = strings.Where(condition);
strings.RemoveAll(kickOut);
var stringsThatDontMeetCondition = strings;
有没有办法只循环原始列表一次来做到这一点?
(highly simplified example)
I have a generic list of strings:
var strings = new List<string> { "abc", "owla", "paula", "lala", "hop" };
I'm looking for the most efficient way to split this list into a list with elements that meet a condition and a list of elements that don't meet that same condition.
Func<string, bool> condition = s => s.IndexOf("o") > -1;
Predicate<string> kickOut = s => s.IndexOf("o") > -1;
var stringsThatMeetCondition = strings.Where(condition);
strings.RemoveAll(kickOut);
var stringsThatDontMeetCondition = strings;
Is there a way to do this with looping only once through the original list?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
使用一些 linq:
更新: 正如评论中提到的,请小心改变列表,因为 linq 方法尝试按需,它们不会迭代列表,直到您开始查看
IEnumerable
。但就我而言,我调用ToList
,这实际上导致它遍历整个项目列表。Use some linq:
Update: as has been mentioned in the comments, be careful mutating the list as linq methods try to be on-demand, they will not iterate the list until you start looking into the
IEnumerable
. However in my case, I callToList
, which effectively causes it to run through the entire list of items.这样就可以了:
但我相信你已经想到了类似的事情。您能否以您寻求的效率更新您的答案?
请注意,在原始列表上使用
pred
和!pred
进行两次过滤仍然是 O(n),而且效率一点也不低。特别是考虑到您将获得两个结果集的惰性求值的全部好处。另请参阅罗布的回答。该算法的时间复杂度为 O(n^2)。
您还可以将它们收集到一个新列表中,并在返回之前将它们复制到输入列表中,而不是删除每个元素。这也将为您带来 O(n)。
O(n) 的另一种选择是切换到链表。
This would do it:
But am sure you have already thought of something similar. Can you please update your answer with the kind of efficiency that you seek?
Note that two filtering runs with
pred
and!pred
over the original list would still be O(n) and not at all inefficient. Especially considering that you'd get the full benefit of lazy evaluation for both result sets. See also Rob's answer.This algorithm is in O(n^2).
Instead removing each element, you can also collect them in a new list and copy them over to the input list before returning. This will also get you O(n).
One more option for O(n) would be switching to a linked list.
为什么不直接使用
当然,您最终会将条件应用于列表中的每个元素两次。为了避免这种情况,您可能需要编写一个通用的拆分函数,但这不会那么简洁。
Why not just use
Of course, you end up applying the condition to each element in the list twice. To avoid this you might want to write a generic splitting function, which wouldn't be as neat.