HashSet не позволяет дублировать в Java, но делает в C# - PullRequest
0 голосов
/ 18 марта 2020

Я работал над проблемой, которая использует тот факт, что HashSet не позволяет дублировать значения. Для этого решение в Java вычисляет несколько HashSet<int>, добавляет их к HashSet<HashSet<int>> и, наконец, возвращает размер. Таким образом, он получает все различные комбинации HashSet. Когда я попытался сделать это в C#, я не получил отчетливый HashSet. Я отладил и вижу два HashSet с одинаковым значением. Как видно на скриншоте ниже.

enter image description here

Так есть ли способ получить такое же поведение в C#, вероятно, с помощью моего собственного компаратора или может быть, даже лучше без него. Я пытался создать свой собственный метод сравнения, но HashSet не имеет индексации, поэтому не уверен, как сравнить два HashSet. Или это не возможно в C#. Одна вещь, которую я заметил, в Java, инициализация выглядит следующим образом:

Set shapes = new HashSet<HashSet<Integer>>();
Set shape = new HashSet<Integer>();

Поскольку в * 1022 нет Set, моя инициализация:

HashSet<HashSet<int>> shapes = new HashSet<HashSet<int>>();
HashSet<int> shape = new HashSet<int>();

Не уверен, что имеет значение.

Ответы [ 2 ]

3 голосов
/ 18 марта 2020

Самый простой способ - сделать свой собственный EqualityComparer, хотя, вероятно, это будет не самый эффективный подход

Пример

public class MyComparer : IEqualityComparer<HashSet<int>>
{
   public bool Equals(HashSet<int> x, HashSet<int> y)
      => x?.SetEquals(y) ?? false;

   public int GetHashCode(HashSet<int> obj)
   {
      unchecked
      {
         return obj.Aggregate(17, (current, item) => current * 31 + item.GetHashCode());
      }
   }
}

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

var rand = new Random();

var hashes = Enumerable.Range(0, 20)
                       .Select(x => new HashSet<int>(Enumerable.Range(0, 3)
                                           .Select(y => rand.Next(0, 5))));


var hashList = new HashSet<HashSet<int>>(hashes, new MyComparer()) ;

foreach (var list in hashList)
   Console.WriteLine(string.Join(", ",list));

Выход

2, 0
3, 1
0, 1, 4
0, 2, 1
0, 3
4, 0, 3
4, 3
0, 1
1, 2
4, 3, 1
2, 1, 0
2
3, 1, 4
3, 2
4, 1, 3
0, 2
1, 4
1, 3

Полная демонстрация здесь

1 голос
/ 19 марта 2020

Причина различия заключается в том, что метод Java HashSet equals (https://docs.oracle.com/javase/7/docs/api/java/util/AbstractSet.html#equals (java .lang.Object) сравнивает содержимое контейнера.

Сравнивает указанный объект с этим набором на равенство Возвращает true, если данный объект также является набором, два набора имеют одинаковый размер и каждый член данного набора содержится в этом наборе. что метод equals правильно работает в различных реализациях интерфейса Set.

. NET HashSet наследует свой метод Equals от Object. Для ссылочных типов просто Object.Equals проверяет равенство ссылок: две передаваемые методу ссылки на самом деле являются ссылками на один и тот же объект в памяти.

В C#, если вы напишите:

var x = new HashSet<int>{2,3,4,5};
var y = new HashSet<int>{2,3,4,5};
var isEqual = x.Equals(y);

Значение isEqual будет False, потому что x и y - это два разных объекта. Эквивалентный код в Java выдаст значение True для isEqual, так как сравнение проверяет содержимое.

* 102 8 * Решение, как указал Майкл Рэндалл в своем ответе, состоит в том, чтобы предоставить свой собственный компаратор.
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...