Как проверить, имеет ли два элемента списка значение равенства с помощью EqualityComparer? [Дубликат]

Предыдущее решение: Как заявил Martijn Pieters, правильный и самый быстрый формат:

if 1 in {x, y, z}:

Одна из основных проблем, которая, похоже, не рассматривается, заключается в том, что вы хотите, чтобы ваш выходной список включают каждое письмо после утверждения if. Используя только совет Martijn Pieters, у вас теперь будет:

if 0 in {x, y, z}:
    Mylist.append("c")
elif 1 in {x, y, z}:
    Mylist.append("d")
...

Проблема: первый оператор if вернет true, и вы никогда не получите следующий оператор elif. Таким образом, ваш список просто вернется:

["c"]

. Вы хотите иметь отдельные операторы if, чтобы python прочитал каждое утверждение, были ли первые правильными или ложными. Например:

if 0 in {x, y, z}:
    Mylist.append("c")
if 1 in {x, y, z}:
    Mylist.append("d")
if 2 in {x, y, z}:
    Mylist.append("e")
...

Это будет работать, но «если» вам удобно использовать словари (см. То, что я там сделал), вы можете очистить это, сделав исходный словарь, сопоставляющий числа с буквами вы хотите, а затем просто используйте цикл 'for':

numToLetters = {0:"c", 1:"d", 2:"e", 3:"f"}
for number in numToLetters:
    if number in {x, y, z}:
        Mylist.append(numToLetters[number])
2
задан HimBromBeere 2 December 2015 в 16:43
поделиться

3 ответа

Фактическая проблема заключается в том, что вы сравниваете два long[], а Enumerable.SequenceEquals будет использовать ObjectEqualityComparer<Int64[]> (вы можете видеть, что, исследуя EqualityComparer<long[]>.Default, который является тем, что внутренне используется Enumerable.SequenceEquals ), который будет сравнивать ссылки этих двух массивов, а не фактические значения , хранящиеся внутри массива, которые, очевидно, не совпадают.

Чтобы обойти это, вы могли бы напишите EqualityComparer<long[]>:

static void Main()
{
    var expected = new List<long[]> 
                       { new[] { Convert.ToInt64(1), Convert.ToInt64(999999) } };
    var actual = DoSomething();

    if (!actual.SequenceEqual(expected, new LongArrayComparer()))
        throw new Exception();
}

public class LongArrayComparer : EqualityComparer<long[]>
{
    public override bool Equals(long[] first, long[] second)
    {
        return first.SequenceEqual(second);
    }

    // GetHashCode implementation in the courtesy of @JonSkeet
    // from http://stackoverflow.com/questions/7244699/gethashcode-on-byte-array
    public override int GetHashCode(long[] arr)
    {
        unchecked
        {
            if (array == null)
            {
                return 0;
            }

            int hash = 17;
            foreach (long element in arr)
            {
                hash = hash * 31 + element.GetHashCode();
            }

            return hash;
        }
    }
}
5
ответ дан Yuval Itzchakov 27 August 2018 в 22:13
поделиться

SequenceEquals тесты для идентичности элементов внутри последовательностей. Элементы в перечислениях имеют тип long[], поэтому мы фактически сравниваем два разных массива (содержащих одни и те же элементы) друг против друга, что наглядно сделано путем сравнения их ссылок вместо их фактического значения.

Итак, что мы на самом деле проверяем здесь, это expected[0] == actual[0] вместо expected[0].SequqnceEquals(actual[0])

Это obiosuly возвращает false, поскольку оба массива используют разные ссылки.

Если мы сглаживаем иерархию с помощью SelectMany, получаем то, что хотим:

if (!actual.SelectMany(x => x).SequenceEqual(expected.SelectMany(x => x))) throw new Exception();

EDIT:

На основе этот подход нашел другое элегантное способ проверить, содержатся ли все элементы из expected в actual:

if (!expected.All(x => actual.Any(y => y.SequenceEqual(x)))) throw new Exception();

Это будет поиск, если на вечном суб-списке внутри expected есть список внутри actual который последовательно идентичен текущему. Это кажется гораздо умнее, так как нам не нужны никакие пользовательские EqualityComparer и не странные хэш-код-реализация.

0
ответ дан Community 27 August 2018 в 22:13
поделиться

Нет, ваши последовательности not равны!

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

var firstExpected = new[] { Convert.ToInt64(1), Convert.ToInt64(999999) };
var firstActual = new[] { Convert.ToInt64(1), Convert.ToInt64(999999) };
Console.WriteLine(firstExpected == firstActual); // writes "false"

Приведенный выше код сравнивает два отдельных массива для равенства. Равенство не проверяет содержимое массивов, проверяет ссылки на равенство.

Ваш код с использованием SequenceEquals, по сути, делает то же самое. Он проверяет ссылки в каждом случае каждого элемента в перечислимом.

4
ответ дан Jamiec 27 August 2018 в 22:13
поделиться
Другие вопросы по тегам:

Похожие вопросы: