Как группировать по пользовательским типам с помощью linq - PullRequest
12 голосов
/ 17 февраля 2010

У меня есть этот класс

public class Item
{
       public Coordinate coordinate { get; set; }
        ...
        ...
}

С определением координаты следующим образом:

public class Coordinate
{
        public Coordinate(float latitude, float longitude)
        {
            Latitude = latitude;
            Longitude = longitude;
        }

        public float Latitude { get; private set; }
        public float Longitude { get; private set; }
}

И я хочу получить запрос linq, подобный этому:

var grouped = from it in items
              group it by it.Coordinate into grp
              select grp;

Как упомянуто здесь MSDN Я подумал, что это возможно, если я переопределю Equals в моем классе координат:

Используйте именованный тип, если вы должны передать переменную запроса другомуметод.Создайте специальный класс, используя автоматически реализованные свойства для ключей, а затем переопределите методы Equals и GetHashCode.Вы также можете использовать структуру, в этом случае вам не обязательно переопределять эти методы.Для получения дополнительной информации см. Практическое руководство. Реализация неизменяемого класса с автоматически реализуемыми свойствами

Равная реализация для класса координат:

public override bool Equals(object obj)
{
       var coord = obj as Coordinate;
       if(coord == null) return false;
       return (Latitude == coord.Latitude && Longitude == coord.Longitude);
}

, однако я не могу получить свой запрос linq для группыпо аналогичным координатам, как показывает мой провальный тест:

[TestMethod]
public void GroupBy_3ItemsWith2DifferentCoordinates_Returns2Groups()
{
    var items = new List<Item>
        {
            new Item {Coordinate = new Coordinate(10, 10)},
            new Item {Coordinate = new Coordinate(10, 10)},
            new Item {Coordinate = new Coordinate(12, 10)},
        };
    var grouped = from it in items
                  group it by it.Coordinate into g
                  select g;
    Assert.AreEqual(2, grouped.Count());
}

Существует перегрузка для метода GrouBy, который принимает IEqualityComparer в качестве параметра, но есть ли эквивалент, использующий предложение group?Я делаю что-то неправильно??Есть мысли?

Ответы [ 2 ]

23 голосов
/ 17 февраля 2010

Вы показали реализацию Equals, но не GetHashCode. Вы должны переопределить оба (и согласованным образом) для группировки для работы.

Пример реализации GetHashCode:

public override int GetHashCode()
{
    int hash = 23;
    hash = hash * 31 + Latitude.GetHashCode();
    hash = hash * 31 + Longitude.GetHashCode();
    return hash;
}

Обратите внимание, что сравнение float значений для точного равенства всегда несколько рискованно - но я бы по крайней мере ожидал, что ваши модульные тесты пройдут, учитывая, что они не выполняют никаких вычислений.

2 голосов
/ 17 февраля 2010

Перегрузка в GrouBy метод, который принимает IEqualityComparer в качестве параметра, но есть ли эквивалентно с помощью предложения группы?

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

var grouped =
  from it in items 
  group it by new {it.Coordinate.Latitude, it.Coordinate.Longitude};
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...