2013-03-01 4 views
8

В C# Я пытаюсь получить элемент из списка по случайному индексу. Когда он был извлечен, я хочу, чтобы он был удален, чтобы он больше не мог быть выбран. Кажется, мне нужно много операций для этого, нет ли функции, в которой я могу просто извлечь элемент из списка? функция RemoveAt (index) недействительна. Я хотел бы получить возвращаемое значение.Удалить элемент из списка и получить элемент одновременно

Что я делаю:

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); 

То, что я хотел бы сделать:

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); 

Существует ли такая функция "removeAndGetItem"?

+0

Вы должны были бы написать ваш собственный - насколько мне известно, только Stack или Queue обладает встроенной функциональностью. Должно ли это быть потокобезопасным? –

+1

Почему бы не получить то, что вы хотите для новой переменной/списка? – Kaf

ответ

15

Нет, поскольку это является нарушением чисто функционального этикета, когда метод имеет либо побочный эффект, либо возвращает полезное значение (то есть не только указывает состояние ошибки), но и то, и другое.

Если вы хотите, чтобы функция появится атомной, вы можете получить получить блокировку в списке, который остановит другие потоки от доступа к списку, пока вы его модификации:

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; 
     } 
    } 
} 
+0

Имейте ввиду, что блокировка будет работать только в том случае, если одновременно вызывается RemoveAndGet. Некоторые другие функции могут изменить список, и вы все равно должны иметь OutOfBoundsException. Как упоминалось ниже, обработка исключений может быть рассмотрена. – mateuscb

+2

первая часть о командах и запросах просто неверна, 'Add' имеет побочные эффекты и возвращает значение в одном и том же классе здесь ... это также не всегда практично, возьмите стек, например,' Pop' имеет побочные эффекты и возвращает значение. это было бы странно, если бы эти двое были разделены. (Мне нравится идея команд и запросов, но эта концепция не применяется в .NET, а не всегда, что вы хотите) –

+0

Лично я считаю, что «полезная» часть моего ответ по-прежнему применяется к возвращенному значению из 'Add', в подавляющем большинстве случаев использования. – RoadieRich

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; 
    } 
} 

Они называются extension methods, называем new List<T>().RemoveAndGetItem(0).

Вещи рассмотреть в методе расширения

Обработка исключений с индексом, который вы передаете, убедитесь, что индекс жгутов 0 и подсчет списка, прежде чем делать это.

+0

+1 Я думаю, это то же самое, что и другой ответ с блокировкой. Спасибо за примечание об обработке исключений. – Eirik

+0

@Eirik Нет спецификации относительно того, что должно произойти, если вы передадите недопустимый индекс методу на IList, поэтому я думаю, что лучше оставить аргумент проверки для реализации списка. Насколько вам известно, пользовательская реализация IList может быть ** ожидающим ** вне диапазона индексов по любой причине. – RoadieRich

+0

@RichardLovely это точная причина, почему я сказал, что это «что-то, чтобы рассмотреть». Кроме того, какие возможности может сделать пользовательский список, ожидающий индекс, который выходит за пределы диапазона, из любопытства? – LukeHennerley

Смежные вопросы