Смысловая структура данных вы ищете часто называют мешок. В сумке, как и в наборе, порядок элементов не имеет значения. Однако в сумке, как и в списке, допускаются повторяющиеся элементы. Таким образом, равенство сумм состоит из того, что каждый из них имеет одинаковые элементы в одинаковых количествах, хотя и не обязательно в одном порядке. Таким образом, кажется, что то, что вы ищете, - это способ применить семантику «сумка» к вашему списку. Самый простой способ сделать это, чтобы дублировать один из мешков и удалите элементы другого мешка из дубликата до: (! Они равны)
- всех элементов другого мешка истощены и дубликат пуст
- все элементы другого мешка исчерпаны, а дубликат НЕ пуст (они разные!)
- Во время итерации один из элементов другого мешка не может быть удален из дубликата (они разные!)
Что-то вроде equals()
реализации, показанной ниже:
class Bag {
List list
Bag(List list) { this.list = list }
@Override boolean equals(that) {
def thisList = list?.clone() ?: []
that instanceof Bag &&
(that?.list ?: []).every { thisList.remove((Object)it) } &&
!thisList
}
@Override int hashCode() { this?.list?.sum { it?.hashCode() ?: 0 } ?: 0 }
@Override String toString() { this?.list?.toString() }
}
def a = [1, 5, 1, -1, 8] as Bag
def b = [5, 1, -1, 8, 1] as Bag // same elements different order
def c = [1, 5, -1, 8] as Bag // same elements different size
def d = [5, 5, 1, -1, 8] as Bag // same elements same size different amounts of each
assert a == b
assert a != c
assert a != d
println a // [1, 5, 1, -1, 8]
println b // [5, 1, -1, 8, 1]
В качестве альтернативы, если вы не заботитесь о первоначальном порядке списка на всех, вы можете представить пакет как карту. Значения элемента суммирования являются ключами карты, а количество появлений каждого элемента мешка - это значения карты. В этот момент равенство - это просто равенство карты.
Как это:
class BagAsMap {
Map map = [:]
BagAsMap(List list) {
(list ?: []).each { map[it] = (map[it] ?: 0) + 1 }
}
@Override boolean equals(that) {
that instanceof BagAsMap && this?.map == that?.map
}
@Override int hashCode() { this?.map?.hashCode() ?: 0 }
@Override String toString() {
'[' + map.keySet().sum { k -> (0..<(map[k])).sum { "${k}, " } }[0..-3] + ']'
}
}
def a1 = [1, 5, 1, -1, 8] as BagAsMap
def b1 = [5, 1, -1, 8, 1] as BagAsMap // same elements different order
def c1 = [1, 5, -1, 8] as BagAsMap // same elements different size
def d1 = [5, 5, 1, -1, 8] as BagAsMap // same elements same size different amounts
assert a1 == b1
assert a1 != c1
assert a1 != d1
println a1
println b1
В любом случае это серьезный перебор, если вам просто нужно проверить порядок нейтрального список эквивалентности один или два раза, но если сумка семантика часто необходима, то определение класс Bag в одном из этих двух способов, вероятно, хорошая идея.
Как указано в другом месте, в данном конкретном случае a.sort() == b.sort()
является достаточной стоп-секундой вместо полной семантики пакета. Однако не все объекты, которые могут быть помещены в список вместе, взаимно сортируются, даже с самым сложным закрытием компаратора. Тем не менее, все они имеют hashCode()
и equals()
. Это все, что необходимо для показанной реализации мешков.
Кроме того, List.sort()
имеет O (N журнал N) алгоритмической сложности, в то время как все операции мешка показанных О (п) сложности. Не стоит беспокоиться об этих небольших списках, но гораздо больше для крупных.
Почему вы не используете 'Set'? – Opal