Как отредактировать элемент списка списков?

#c# #linq #list

#c# #linq #Список

Вопрос:

У меня есть:

 var list = new List<List<MyClass>>();
  

MyClass :

 public class MyClass
{
  public double X { set; get; }
  public double Y { set; get; }
  public bool Unique{ set; get; }
}
  

Теперь у меня есть double x и double y , и я хочу найти элемент списка с таким же X and Y и установить Unique для поля значение false.

Я уже нахожу примеры для поиска, такие как:

 var element = (from sublist in list
               from item in sublist
               where item.X == x amp;amp; item.Y == y
               select item).FirstOrDefault();
  

Но как отредактировать этот элемент?

Уверен, я могу сделать что-то вроде:

 foreach (var myClsList in list)
{
  foreach (var myCls in myClsList )
  {
    if (myCls.X == x amp;amp; myCls.Y == y)
    {
      myCls.Unique= false;
    }
  }
}
  

Но это выглядит не очень красиво.

Комментарии:

1. Как бы вы обычно его редактировали?

2. Выглядит так же красиво или «круто»?

Ответ №1:

Похоже, вы действительно хотите сгруппировать элементы по их X и Y свойствам и правильно установить Unique свойства внутри этих групп. Вот несколько первоначальных мыслей:

 List<Element> allItems = list.SelectMany(l => l);
var groups = allItems.GroupBy(element => new { X = element.X, Y = element.Y });
foreach (var group in groups) {
    bool unique = group.Count() == 1;
    foreach (var element in group) {
        element.Unique = unique;
    }
}
  

Ответ №2:

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

Для одного элемента вы делаете:

 (from sublist in list
 from item in sublist
 where item.X == x amp;amp; item.Y == y
 select item).First().Unique = false; //the default item will be null
  

Это работает, но довольно уродливо. Лучше:

 var element = (from sublist in list
               from item in sublist
               where item.X == x amp;amp; item.Y == y
               select item).FirstOrDefault();
element.Unique = false;
  

Чтобы изменить их все, используйте foreach . Linq на самом деле не предназначен для побочных эффектов. Это должна быть конструкция с побочным эффектом. В вашем случае я бы сделал:

 var query = list.SelectMany(sublist => sublist)
                .Where(item => item.X == x amp;amp; item.Y == y);
foreach(var myClass in query)
    myClass.Unique = false;
  

Если вам действительно нужны побочные эффекты и вы хотите сделать это в стиле linq, вы можете лучше использовать свободный стиль, настроив свой MyClass следующим образом:

 public class MyClass
{
  public double X { set; get; }
  public double Y { set; get; }
  public bool Unique { set; get; }

  public MyClass Duplicate()
  {
    Unique = false;
    return this;
  }
}

// So you call:

var query = list.SelectMany(sublist => sublist)
                .Where(item => item.X == x amp;amp; item.Y == y)
                .Select(item => item.Duplicate());
  

Ответ №3:

Некоторые мысли об общей структуре:

Посмотрите на класс Dictionary<> . Это предназначено для хранения списка элементов, к которым можно получить доступ через произвольный тип. Чтобы использовать его в этом контексте:

  • Удалите Unique из вашего класса.
  • Вместо этого сделайте свой класс структурой, чтобы он сравнивался по значению, а не по ссылке (т. Е. два разных класса MyClasses с одинаковыми X / Y считаются одинаковыми)
  • Вместо списка используйте Dictionary<MyClass, bool>

(кажется, здесь нужен текст для создания блока кода)

 public struct MyClass
{
    public double X { get; set; }
    public double Y { get; set; }
}

var items = new Dictionary<MyClass, Bool>();

items[ new MyClass{ X = 3, Y = 7 } ] = false;
items[ new MyClass{ X = -12, Y = -24 } ] = true;

Assert.IsFalse( items[ new MyClass{ X = 3, Y = 7 } ] );
Assert.IsTrue( items[ new MyClass{ X = -12, Y = -24 } ] );

items[ new MyClass{ X = 3, Y = 7 } ] = true;
Assert.IsTrue( items[ new MyClass{ X = 3, Y = 7 } ] );
  

Чтобы прояснить, как работает словарь:

  • K — это тип «key»; это тип, используемый для обозначения элементов, которые вы сохраняете в словаре, и используется как при добавлении элементов в него, так и при извлечении элементов из него.
  • V — это тип «значение»; это тип, который вы сохраняете.
  • Вы можете прочитать или записать словарь, используя индексатор:
    • значение var = dictionary[ключ]
    • словарь [ключ] = значение
  • При некоторых обстоятельствах словарь может быть быстрее, чем ручная итерация по списку, поскольку он внутренне может использовать любую структуру данных, которая ему нравится, для поиска совпадений, что может быть быстрее для больших наборов данных. Я полагаю, что он использует GetHashCode для сокращения совпадений, но это, вероятно, неважно в данном контексте.