Nano Hash - криптовалюты, майнинг, программирование

Перебрать список итераторов linq

Перечислители списков не работают в случае, если они помещены в список. Например, в случае двух списков (два счетчика)

public void test()
{
    var firstList = new List<int>() { 1, 2, 3 };
    var secondList = new List<int>() { 4, 5, 6 };
    var lists = new List<List<int>>();
    lists.Add(firstList);
    lists.Add(secondList);

    // Not working
    var iterators = lists.Select(x => x.GetEnumerator()).ToList();
    iterators.ForEach(x => x.MoveNext());
    iterators.ForEach(x => Console.WriteLine(x.Current));

    // Working
    var firstIterator = iterators[0]; 
    var secondIterator = iterators[1];
    firstIterator.MoveNext(); secondIterator.MoveNext();
    Console.WriteLine(firstIterator.Current);
    Console.WriteLine(secondIterator.Current);
}

первая часть не работает и печатает 0 0, а вторая часть работает и печатает 1 4.

Я не понимаю, в чем ошибка с первой частью и как ее можно решить.

26.05.2017

  • вам специально нужно использовать итераторы? 26.05.2017
  • x и iterators[0] не совпадают. x является локальной копией в каждом вызове ForEach. 26.05.2017

Ответы:


1

Это связано с тем, что метод List<T>.GetEnumerator возвращает List<T>.Enumerator изменяемая структура .

Когда вы присваиваете его переменной и вызываете MoveNext и Current, он работает. Но при передаче делегату он передается по значению, поэтому делегат получает копию, поэтому вызов MoveNext не влияет на исходный struct Current.

Просто один из побочных эффектов изменяемых структур.

Если вы измените

x => x.GetEnumerator()

to

x => (IEnumerator<int>)x.GetEnumerator()

or

x => x.AsEnumerable().GetEnumerator()

оба фрагмента будут работать, потому что теперь iterators будет содержать упакованные ссылки на возвращаемые структуры.

26.05.2017
  • Оба варианта рабочие. Спасибо за решение. 26.05.2017

  • 2

    Это потому, что вы запускаете 2 отдельных .ForEach() в нерабочей части. Выполните оба действия в 1 foreach (MoveNext(), затем напечатайте). MoveNext не будет запомнен в .Foreach() для хорошего объяснения: Перейти к этому ответу

    Это:

    iterators.ForEach(x => x.MoveNext());
    iterators.ForEach(x => Console.WriteLine(x.Current));
    

    становится:

    iterators.ForEach(x => { x.MoveNext(); Console.WriteLine(x.Current); });
    
    26.05.2017
  • Это не объясняет, почему итераторы остаются в состоянии по умолчанию после первого ForEach. 26.05.2017
  • Мне нужно перемещать и использовать итераторы, чтобы быть в другой строке. Кроме того, если я сделаю iterators[0].MoveNext();, а затем в следующей строке iterators[0].Current, это тоже не сработает. 26.05.2017
  • @Petar Может быть, указать это? Ищу вас сейчас для лучшего решения 26.05.2017
  • @Petar Иван имеет решение 26.05.2017

  • 3

    Перечислитель списка реализован как тип значения (исходный код):

    iterators[0].GetType().IsValueType // true
    

    Это означает, что итераторы передаются по значению, когда вы передаете их методам (т.е. копия итератора передается вместо передачи ссылки на экземпляр итератора). ForEach просто выполняет действие в цикле:

    iterators.ForEach(copy => copy.MoveNext());
    

    Делегат действия — это метод, поэтому вы передаете этому методу копию каждого итератора. Таким образом, исходные итераторы остаются неизменными. И когда вы вызываете ForEach во второй раз, туда снова передаются копии исходных нетронутых итераторов:

    iterators.ForEach(newCopy => Console.WriteLine(newCopy.Current));
    

    Но исходные итераторы находятся в начальном состоянии (до первого элемента), поэтому вы видите значения по умолчанию целочисленного типа, когда читаете значение Current.

    Вы можете работать с одной копией итератора:

    iterators.ForEach(copy => { copy.MoveNext(); Console.WriteLine(copy.Current); });
    

    Или тип значения поля, чтобы передать его по ссылке (обратите внимание, что тип списка iterators изменится):

    var iterators = lists.Select(x => (IEnumerable<int>)x.GetEnumerator()).ToList();
    
    26.05.2017
    Новые материалы

    Кластеризация: более глубокий взгляд
    Кластеризация — это метод обучения без учителя, в котором мы пытаемся найти группы в наборе данных на основе некоторых известных или неизвестных свойств, которые могут существовать. Независимо от..

    Как написать эффективное резюме
    Предложения по дизайну и макету, чтобы представить себя профессионально Вам не позвонили на собеседование после того, как вы несколько раз подали заявку на работу своей мечты? У вас может..

    Частный метод Python: улучшение инкапсуляции и безопасности
    Введение Python — универсальный и мощный язык программирования, известный своей простотой и удобством использования. Одной из ключевых особенностей, отличающих Python от других языков, является..

    Как я автоматизирую тестирование с помощью Jest
    Шутка для победы, когда дело касается автоматизации тестирования Одной очень важной частью разработки программного обеспечения является автоматизация тестирования, поскольку она создает..

    Работа с векторными символическими архитектурами, часть 4 (искусственный интеллект)
    Hyperseed: неконтролируемое обучение с векторными символическими архитектурами (arXiv) Автор: Евгений Осипов , Сачин Кахавала , Диланта Хапутантри , Тимал Кемпития , Дасвин Де Сильва ,..

    Понимание расстояния Вассерштейна: мощная метрика в машинном обучении
    В обширной области машинного обучения часто возникает необходимость сравнивать и измерять различия между распределениями вероятностей. Традиционные метрики расстояния, такие как евклидово..

    Обеспечение масштабируемости LLM: облачный анализ с помощью AWS Fargate и Copilot
    В динамичной области искусственного интеллекта все большее распространение получают модели больших языков (LLM). Они жизненно важны для различных приложений, таких как интеллектуальные..


    © 2024 nano-hash.ru, Nano Hash - криптовалюты, майнинг, программирование