Группировать по содержимому массива

У меня есть List<Tuple<string,long,byte[]>>, и я хочу сгруппировать по содержимому массива байтов.

Есть ли простой способ сделать это с помощью GroupBy и лямбды?

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


person soandos    schedule 05.04.2013    source источник
comment
Чем вы надеетесь закончить? Если вы получите отдельные байтовые элементы в качестве ключа, каким будет остальная часть вашего результата?   -  person itsme86    schedule 05.04.2013
comment
Я надеюсь, что элементы в моем списке будут сгруппированы по содержимому этого массива. т.е. если массивы равны, то они в одной группе, иначе в разных группах.   -  person soandos    schedule 05.04.2013
comment
Вы определяете равенство для массивов как ссылку на один и тот же массив или наличие одинаковых байтов в разных массивах? Если последнее, вам нужно определить собственный компаратор равенства для byte[].   -  person Servy    schedule 05.04.2013
comment
@Серви, второй. Как я могу сделать это в лямбде?   -  person soandos    schedule 05.04.2013
comment
@soandos Ты не можешь. Вам нужно создать новый класс, реализующий IEqualityComparer<byte[]>, реализовать оба метода, создать его экземпляр и передать его в GroupBy.   -  person Servy    schedule 05.04.2013
comment
@Servy, почему бы и нет, и как мне это сделать?   -  person soandos    schedule 05.04.2013
comment
@soandos Вы можете использовать IEnumerable<T>.SequenceEqual() (msdn.microsoft.com/en-us/library /bb348567.aspx)   -  person itsme86    schedule 05.04.2013
comment
@itsme86 Вам также нужно получить хэш-код.   -  person Servy    schedule 05.04.2013
comment
@itsme86 itsme86, как я могу использовать это в контексте лямбды? У меня только один аргумент. Servy, хэш-код для массивов так же хорош, как и сравнение ссылочного равенства.   -  person soandos    schedule 05.04.2013


Ответы (1)


Вы можете добиться этого, используя собственную IEqualityComparer<byte[]> (или, что еще лучше, общую: IEqualityComparer<T[]>) реализацию:

class ArrayComparer<T> : IEqualityComparer<T[]>
{
    public bool Equals(T[] x, T[] y)
    {
        return x.SequenceEqual(y);
    }

    public int GetHashCode(T[] obj)
    {
        return obj.Aggregate(string.Empty, (s, i) => s + i.GetHashCode(), s => s.GetHashCode());
    }
}

Я почти уверен, что GetHashCode можно было бы реализовать намного лучше, но это всего лишь пример!

Использование:

var grouped = source.GroupBy(i => i.Item3, new ArrayComparer<byte>())
person MarcinJuraszek    schedule 05.04.2013
comment
Это не очень эффективный метод генерации хэш-кода, но он будет работать. - person Servy; 05.04.2013
comment
Как я уже сказал - это просто пример. - person MarcinJuraszek; 05.04.2013
comment
Скорее всего, OP не узнает, что ваш метод GetHashCode не очень хорош, или как его исправить; он просто проверит это один или два раза, увидит правильный результат и больше никогда к нему не прикоснется. - person Servy; 05.04.2013
comment
Для чего используется метод GetHashCode (в отличие от equals)? - person soandos; 05.04.2013
comment
@soandos Это хорошо описано в MSDN: Object.GetHashCode Method - person MarcinJuraszek; 05.04.2013
comment
Как это обрабатывается, если хэш-коды равны, а объекты - нет? (Я буду использовать это в случае, когда есть не менее 600 000 объектов или около того) - person soandos; 05.04.2013
comment
@soandos Он использует Equals, чтобы определить, фактически они равны, когда хэши сталкиваются. - person Servy; 05.04.2013
comment
Тогда используется метод Equals. - person MarcinJuraszek; 05.04.2013
comment
Таким образом, по сути, хеш-код не должен быть очень хорошим, если массивы короткие (время, необходимое для создания строк, будет намного выше, если массив имеет размер только 4 или около того)? - person soandos; 05.04.2013
comment
@soandos Хэш-код никогда не должен быть хорошим. Насколько он хорош, определяет эффективность операции. В этом случае для создания хеш-кода требуется много времени и памяти, а частота коллизий гораздо выше, чем могла бы быть. Все это плохие свойства для хэш-кода. Ни один из них не приведет к неправильному выводу, просто медленное выполнение по мере увеличения размера данных, а также количества элементов. - person Servy; 05.04.2013
comment
@Servy имеет смысл. Я думаю, что я собираюсь профилировать результаты этой хеш-функции только с помощью return obj[0], так как в моем случае они случайны, а проверка на равенство короткая. - person soandos; 05.04.2013
comment
@soandos Это может быть хорошей идеей. Затем вы будете выполнять итерацию в методе Equals (для того же первого элемента), что занимает столько же времени, сколько и вычисление HashCode из всего содержимого массива. - person MarcinJuraszek; 05.04.2013
comment
@Servy Можете ли вы предложить лучшую реализацию GetHashCode? - person julealgon; 27.02.2015
comment
@julealgon Это довольно хорошо решенная проблема; небольшое базовое исследование по этому вопросу приведет к ряду простых хорошо подходящих алгоритмов для различных ситуаций. - person Servy; 27.02.2015
comment
@Servy Но это сэкономило бы нам все время и помогло бы завершить этот ответ, просто предложив то, что, по вашему мнению, является лучшим решением для этой ситуации в первую очередь. - person xr280xr; 24.04.2021