获取序列中“下一个”元素的最简单方法是什么?

时间:2011-12-21 00:46:40

标签: c# .net linq c#-4.0 icollection

我有ICollection<SomeClass>

public class SomeClass
{
   public string Text { get; set; }
   public bool IsPreferred { get; set; }
}

那里的物品已经预订,所以“下一步”确实意味着什么。

在我的场景中,序列的内容如下所示:

  

[0] - “a”,false

     

[1] - “b”,true

     

[2] - “c”,false

我正试图在IsPreferred == true之后得到“下一个”元素。所以在上面,我想得到元素2,我想清除其他IsPreferred值。

所以我想最终得到这个:

  

[0] - “a”,false

     

[1] - “b”,false

     

[2] - “c”,true

基本上将首选项目洗牌。

最好的方法是什么?我唯一能想到的是创建一个新数组,逐个添加它们,跟踪首选数据的索引,然后在上述索引+1处获取元素。

有更好的想法吗?

5 个答案:

答案 0 :(得分:5)

我会使用枚举器来迭代集合 - 这就是foreach在幕后所做的事情:

var enumerator = collection.GetEnumerator();

while (enumerator.MoveNext())
{
    if (enumerator.Current.IsPreferred)
    {
        var oldPreferred = enumerator.Current;

        if (enumerator.MoveNext())
        {
            oldPreferred.IsPreferred = false;
            enumerator.Current.IsPreferred = true;
        }

        break;
    }
}

这确实假设你想在找到带有IsPreferred的第一个项目后停止,如果这是最后一个项目,仍然清楚IsPreferred。

编辑:固定边缘情况,其中IsPreferred总是在单个项目的集合上设置为false

答案 1 :(得分:4)

由于ICollection<T>没有给你一个索引器,我会选择更直接的解决方案而不是依赖LINQ。

假设您希望(1)在条件满足后立即停止,并且(2)仅在下一个项目存在时更改该值,这可以通过以下方式实现:

bool isFound = false;
SomeClass targetItem = null;
foreach (var item in list)
{
    if (isFound)
    {
        item.IsPreferred = true;
        targetItem.IsPreferred = false;
        break;
    }
    if (item.IsPreferred)
    {
        targetItem = item;
        isFound = true;
    }
}

答案 2 :(得分:3)

我只能想到用LINQ做一个混乱的方式:

var x = collection.SkipWhile(z => !z.IsPreferred);
SomeClass a = x.First();
SomeClass b = x.Skip(1).First();

a.IsPreferred = false;
b.IsPreferred = true;

这当然不包括错误检查,效率不高。


另一种可能性(使用LINQ)将使用Ahmad Mageed的解决方案(如下面的评论所示):

var x = collection.SkipWhile(z => !z.IsPreferred);
SomeClass a = x.FirstOrDefault();
SomeClass b = x.ElementAtOrDefault(1);

if (a != null) a.IsPreferred = false;
if (b != null) b.IsPreferred = true;

答案 3 :(得分:0)

一些想法

  1. 如果你可以遍历集合,为什么我们不能在处理i + 1之前将i + 2值设置为true?一定要确保i + 2存在
  2. 另一个想法是扩展LinkedList并使current.next.next = true(如果存在)。

答案 4 :(得分:0)

由于您的收藏是订购的,它可以是IList而不是ICollection吗?

然后,您可以创建一个扩展方法,为您提供某些谓词适用的值的索引:

static IEnumerable<int> IndexWhere<T>(this IList<T> list, 
                                      Func<T, bool> predicate)
{
    for(int i = 0; i < list.Count; i++)
    {
        if(predicate(list[i])) yield return i;
    }
}

假设您只希望一个元素匹配,听起来其余元素就像这样:

var preferredIndex = list.IndexWhere(x=>x.IsPreferred).Single();
list[preferredIndex].IsPreferred = false;
list[preferredIndex + 1].IsPreferred = true;