获取下一个元素或获取第一个元素的List<>方法

18
我想获取列表中的下一个元素,如果列表已经到了末尾,我希望得到第一个元素。 换句话说,我只是希望它循环。
   List<int> agents = taskdal.GetOfficeAgents(Branches.aarhusBranch);
    if (lastAgentIDAarhus != -1)
    {
        int index = agents.IndexOf(lastAgentIDAarhus);
        if (agents.Count > index + 1)
        {
            lastAgentIDAarhus = agents[index + 1];
        }
        else
        {
            lastAgentIDAarhus = agents[0];
        }
    }
    else
    {
        lastAgentIDAarhus = agents[0];
    }

我对我上面展示的解决方案相当不满意,如果你有更好的解决方案,请告诉我 :)

7个回答

24
lastAgentIDAarhus = agents[index == -1 ? 0 : index % agents.Count];

使用MOD运算符%会自动将索引截取到可能的索引范围内。

模除运算符是DIV(/)运算符的补充,返回两个整数相除的余数。例如,如果你将9除以6,结果是1,余数为3。MOD运算符要求得到这个余数。


哇,如果那个方案能够运行,那就非常棒了 :) 可以详细解释一下吗? - The real napster
模运算符执行模运算,这正是您想要的。如果您可以将索引初始化为0而不是-1,则可以使用:lastAgentIDAarhus = agents[index % (agents.Count - 1)]。 - configurator
3
我认为应该是 index % ( agents.Count ) - Eric Yin
3
你的 Count 属性将始终比你所拥有的最高索引高1。这是因为(通常情况下)索引从0开始,而 Count 属性从1开始计算。 - ThaMe90
1
@EricYin 是正确的。假设你有一个包含10个项目的列表,并尝试访问索引为10的项目(它不存在)。10%10=0是你想要的,而不是10%9=1。 - Forss
从问题中发布的代码我们可以看到TS需要agents[0],而不是agents[1]。因此没有必要减去-1,我建议进行编辑。 - Necronomicron

15
或者简单地说:
public static T NextOf<T>(this IList<T> list, T item)
{
    var indexOf = list.IndexOf(item);
    return list[indexOf == list.Count - 1 ? 0 : indexOf + 1];
}

例子:

List<string> names = new List<string>();

names.Add("jonh");
names.Add("mary");

string name = String.Empty;    

name = names.NextOf(null);   //name == jonh

name = names.NextOf("jonh"); //name == mary

name = names.NextOf("mary"); //name == jonh

6
作为稍微不同的方法,这里有一个扩展方法可以用来使任何IEnumerable“循环”。
  public static IEnumerable<T> AsCircularEnumerable<T>(this IEnumerable<T> enumerable)
  {
    var enumerator = enumerable.GetEnumerator();
    if(!enumerator.MoveNext())
      yield break;

    while (true)
    {
      yield return enumerator.Current;
      if(!enumerator.MoveNext())
        enumerator = enumerable.GetEnumerator();
    }
  }

你可以像这样使用它

  var agents = new List<int> {1, 2, 3, 4, 123, 234, 345, 546};

  foreach(var i in agents.AsCircularEnumerable())
  {
    Console.WriteLine(i);
  }

这将会持续不断地进行...... :)


如果列表中有3个元素,并且我使用索引值4或5来获取列表中的一个项目,那么我会得到列表的第一个和第二个元素吗? - BenKoshy
我不确定你的意思。如果你是在问关于使用我上面概述的解决方案进行索引的问题,那么,由于这不是列表而是IEnumerable,并且你不能在IEnumerable上使用索引器,那么不,你不能。你可以使用像agents.AsCircularEnumerable().Skip(10).First()这样的东西。 - Steve Willcock

4

我喜欢Vinicius提出的使用扩展方法的想法。不幸的是,他发布的代码会抛出异常。以下代码基于他的代码,但不会抛出异常,而且非常简单易懂(在我看来):

public static T Next<T>(this IList<T> list, T item)
{
    var nextIndex = list.IndexOf(item) + 1;

    if (nextIndex == list.Count)
    {
        return list[0];
    }

    return list[nextIndex];
}

如果传入的项不在列表中,则它将返回列表中的第一项,因为在这种情况下 list.IndexOf(item) 将返回 -1

Koveras,哪里会引发异常? - Vinicius Gonçalves
请记住,如果未找到任何项,则list.IndexOf(item)将返回-1。 - Vinicius Gonçalves
这是一个非常好的扩展想法。我稍微修改了一下并实现了它 :) - etalon11

2

如果我们增加一些检查来避免常见的错误,你觉得怎么样?

public static class ListExtensions
{
    public static TType Next<TType>(this IList<TType> list, TType item)
    {
        if (list == null) return default(TType);

        var itemIndex = list.IndexOf(item);
        if (itemIndex < 0) return list.FirstOrDefault();

        var nextIndex = itemIndex + 1;

        return nextIndex >= list.Count 
            ? list.FirstOrDefault() 
            : list[nextIndex];
    }
}

2

虽然差别不大,但至少减少了一些代码(至少在编辑器中);o)

List<int> agents = taskdal.GetOfficeAgents(Branches.aarhusBranch);
if (lastAgentIDAarhus != -1)
{
    int index = agents.IndexOf(lastAgentIDAarhus);
    lastAgentIDAarhus = (agents.Count > index + 1 ? agents[index + 1] : agents[0]); 
}
else
{
    lastAgentIDAarhus = agents[0];
}

-4

string line = lines[lines.FindIndex(x => x.Contains(item)) + 1];

字符串line = lines[lines.FindIndex(x => x.Contains(item)) + 1];


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接