IEnumerable<int> list = new[] { 1, 2, 7, 3, 11, 5 };
int item = (from x in list where (x == list.Max()) select x).First();
IEnumerable<int> above = from x in list where list.ToList().IndexOf(item) > list.ToList().IndexOf(x) select x;
IEnumerable<int> below = from x in list where list.ToList().IndexOf(item) < list.ToList().IndexOf(x) select x;
我想在IEnumerable
中找到一个元素,并将IEnumerable
拆分为不再包含我找到的元素的IEnumerable
。上面的代码说明了我想要实现的结果,但是我必须将IEnumerable转换为List。
我觉得必须有一种方法可以使用LinQ和IEnumerable来做到这一点。 怎么办呢?
答案 0 :(得分:14)
所以我们这里有几个子问题。第一个问题是返回一个集合中的项目,该集合具有该项目的某些投影的最高值。 Max
仅比较项目本身,或者,如果给定投影,则返回该投影的结果。
public static TSource MaxBy<TSource, TKey>(this IEnumerable<TSource> source
, Func<TSource, TKey> selector
, IComparer<TKey> comparer = null)
{
if (comparer == null)
{
comparer = Comparer<TKey>.Default;
}
using (IEnumerator<TSource> iterator = source.GetEnumerator())
{
if (!iterator.MoveNext())
{
throw new ArgumentException("Source was empty");
}
TSource maxItem = iterator.Current;
TKey maxValue = selector(maxItem);
while (iterator.MoveNext())
{
TKey nextValue = selector(iterator.Current);
if (comparer.Compare(nextValue, maxValue) > 0)
{
maxValue = nextValue;
maxItem = iterator.Current;
}
}
return maxItem;
}
}
这使我们能够更有效地获得具有最大值的项目的索引:
var splitPoint = list.Select((index, number) => new { index, number })
.MaxBy(pair => pair.number)
.index;
在拆分集合旁边,您只需使用skip / take:
var firstHalf = list.Take(index);
var secondHalf = list.Skip(index + 1);
您在此处解决的代码存在许多不同的问题。
您为查询中的每个项计算Max
值以获取item
,而不是计算一次并使用该计算值。
然后,对于列表中的每个项目,然后将所有项目复制到新列表,两次,搜索该列表以尝试查找最大项目的位置,并且然后尝试找到当前项目的位置。然后,你做了两次。这意味着您将每个项目的整个数组复制到列表中四次,在集合中每个项目搜索最多项目的位置四次,并线性搜索列表以查找当前项目的索引(某些内容)你可以在几乎没有时间计算每个项目只计算两次。随着物品数量的增加,这将会很难......。
此处的代码在集合的单个过程中查找最大项目的索引,然后创建表示每个半部分的序列,除了简单地遍历这些项目之外,每个部分几乎没有任何开销。
答案 1 :(得分:4)
尝试使用可以使用索引的扩展方法。请看下面的评论示例。
// define the list
IEnumerable<int> list = new[] { 1, 2, 7, 3, 11, 5 };
// define some value (max in your sample)
int value = list.Max();
// get the index of the value you want
int indexValue = list.ToList().IndexOf(value);
// find collections
IEnumerable<int> above = list.Where((value, index) => index < indexValue);
IEnumerable<int> below = list.Where((value, index) => index > indexValue);
答案 2 :(得分:3)
首先,您需要找到最大元素的(第一个)索引。作为Servy答案的变体,可以使用Select
和Aggregate
来完成。然后枚举该索引之前和之后的元素:
var indexOfMax = list
.Select((value, index) => new KeyValuePair<int, int>(index, value))
.Aggregate(new KeyValuePair<int, int>(-1, -1), (min, cur) =>
{
if (min.Key == -1 || cur.Value > min.Value)
return cur;
return min;
}).Key;
var beginning = list.Take(indexOfMax);
var end = list.Skip(indexOfMax + 1);
答案 3 :(得分:0)
首先,您需要保证您的IEnumerable<T>
对象包含某些特定顺序的项目。这可以通过使用IOrderedEnumerable<T>
代替普通无序IEnumerable<T>
,或者使用可以通过索引引用元素的IList<T>
来完成。
当你想到这一点时,拆分变得非常简单:按索引或顺序遍历元素并将它们添加到IList<T> above
,直到找到你的元素。跳过该元素,然后继续迭代元素,同时将它们添加到IList<T> below
。