从列表中删除项目并同时获取该项目

Eir*_*rik 11 c# list

在C#中,我试图通过随机索引从列表中获取项目.检索完后,我希望将其删除,以便不再选择它.好像我需要很多操作才能做到这一点,是不是我可以从列表中简单地提取项目?RemoveAt(index)函数为void.我想要一个具有返回值的人.

我在做什么:

List<int> numLst = new List<int>();
numLst.Add(1);
numLst.Add(2);

do
{
  int index = rand.Next(numLst.Count);
  int extracted = numLst[index]; 
  // do something with extracted value...
  numLst.removeAt(index);
}
while(numLst.Count > 0);
Run Code Online (Sandbox Code Playgroud)

我想做什么:

List<int> numLst = new List<int>();
numLst.Add(1);
numLst.Add(2);

do
{
  int extracted = numLst.removeAndGetItem(rand.Next(numLst.Count)); 
  // do something with this value...
}
while(numLst.Count > 0);
Run Code Online (Sandbox Code Playgroud)

这样的"removeAndGetItem"函数是否存在?

Roa*_*ich 16

不,因为它违反了纯函数礼仪,其中一个方法要么具有副作用,要么返回一个有用的值(即不只是指示错误状态) - 从不两者兼而有之.

如果希望函数显示为原子,则可以获取列表上的锁定,这将阻止其他线程在修改时访问列表:

public static class Extensions
{
    public static T RemoveAndGet<T>(this IList<T> list, int index)
    {
        lock(list)
        {
            T value = list[index];
            list.RemoveAt(index);
            return value;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 请记住,只有同时调用 RemoveAndGet 时,锁才会有帮助。其他一些函数仍然可以修改列表,并且您仍然会遇到 OutOfBoundsException。如下所述,可以考虑异常处理。 (2认同)
  • 关于命令和查询的第一部分是不正确的,"添加"有副作用,并在这里的同一个类上返回一个值......它也不总是实用的,例如以一个堆栈为例,"Pop"有副作用,返回一个值.保持这两个分开是很奇怪的..(我确实喜欢命令和查询的想法,但这个概念并没有在.NET中强制执行,并不总是你想要的) (2认同)
  • 此答案中的 lock() 无关紧要且具有误导性。任何其他线程都可以修改该列表。 (2认同)

Luk*_*ley 5

public static class ListExtensions
{
  public static T RemoveAndGetItem<T>(this IList<T> list, int iIndexToRemove}
  {
    var item = list[iIndexToRemove];
    list.RemoveAt(iIndexToRemove);
    return item;
  } 
}
Run Code Online (Sandbox Code Playgroud)

这些被称为扩展方法,称为new List<T>().RemoveAndGetItem(0).

扩展方法中要考虑的事项

使用您传递的索引进行异常处理,在执行此操作之前检查索引是否为0以及列表的计数.

  • @LukeHennerley例如,一个似乎循环包裹的列表?我们应该假设所有程序员都是理智的 - 或者看起来疯狂的东西不仅仅是真正的天才? (2认同)