Обновить элемент в IEnumerable

мне нужно обновить значение в списке IEnumerable.

вот краткий пример IEnumerable:

IEnumerable<string> allsubdirs = new List<string>() { "a", "b", "c" };

теперь, если я хочу добавить метку времени к каждому элементу, это не работает:

allsubdirs.Select(a => a = a + "_" + DateTime.Now.ToString("hhmmss")).ToList();

не так:

foreach (var item in allsubdirs)
            item = item + "_" + DateTime.Now.ToString("hhmmss");

Я заставил его работать так:

IEnumerable<string> newallsubdirs = allsubdirs.Select(a => a + "_" + DateTime.Now.ToString("hhmmss")).ToList();
        allsubdirs = newallsubdirs;

но это как-то похоже на обман. Как правильно это сделать, пожалуйста?

5 ответов


Linq для запрос, а не обновление. Запросы Linq возвращают новая собрание основанное на проекциях, фильтрах etc. Таким образом, ваш выбор:

  • сохраните коллекцию" new " обратно в переменную (или новую переменную, если необходимо):

    allsubdirs = allsubdirs.Select(a => a = a + "_" + DateTime.Now.ToString("hhmmss")).ToList();
    
  • используйте интерфейс для записи, например IList<T> и for петли:

    IList<string> allsubdirs = new List<string>() { "a", "b", "c" };
    
    for(int i=0; i<allsubdirs.Count(); i++)
        allsubdirs[i] = allsubdirs[i] + "_" + DateTime.Now.ToString("hhmmss");
    

главное отличие в том, что Select не изменяет исходную коллекцию, а for loop делает.

мое мнение:Select чище и не "обманывает" - вы просто добавляете проекцию поверх оригинальной коллекции.


ваша первая попытка

allsubdirs.Select(a => a = a + "_" + DateTime.Now.ToString("hhmmss")).ToList();

возвращает новый IEnumerable но не меняет старый. Для этого используйте

allsubdirs = allsubdirs.Select(a => a + "_" + DateTime.Now.ToString("hhmmss")).ToList();

попробуйте это:-

var result= allsubdirs.Select(x => String.Format("{0}_{1}", x,
                                      DateTime.Now.ToString("hhmmss")));

Если вы не хотите, чтобы сохранить его в другой переменной, рассмотрите возможность использования ToList().


как упоминалось в существующих ответах, an IEnumerable коллекцию нельзя изменить, пытаясь присвоить новое значение одному из ее элементов.

однако, если элементы, содержащиеся в коллекции, имеют изменяемый тип, их можно изменить. Но для вашего примера это невозможно, потому что a string - это непреложно.

так что если вы хотите изменить существующие элементы в IEnumerable, сам элемент должен быть типом, поддерживающим операции модификации, как в ниже приведен пример.

public class MyItem
{
    private string _value;

    public MyItem(string content)
    {
        _value = content;
    }
    public void Append(string other)
    {
        _value += other;
    }
    public void ReplaceWith(Func<string, string> replacer)
    {
        _value = replacer(_value); 
    }
}

тогда вы можете использовать его так:

IEnumerable<MyItem> allsubdirs = new List<MyItem>() { new MyItem("a"), new MyItem("b"), new MyItem("c") };

foreach (var item in allsubdirs)
        item.Append("_" + DateTime.Now.ToString("hhmmss"));

D Stanley ответил правильно. Я хотел бы добавить к его ответу, так как название Update item in IEnumerable подразумевается, что должен быть обновлен только один элемент.

As D Stanely в своем ответ:

Linq предназначен для запросов, а не для обновления.

и

используйте записываемый интерфейс, такой как IList и цикл for

для обновления одного элемента, вы можете извлеките индекс элемента для обновления и используйте этот индекс для его обновления.

например:

IList<string> allsubdirs = new List<string>() { "a", "b", "c" };
int index = allsubdirs.IndexOf("a");
allsubdirs[index] = "d";