Ruby: Массивы как множества
В работе над массивами есть особый набор операций, который пришли к нам из математики – это операции над множествами. В Ruby для такого случая есть специальные операторы, близкие к их математическим эквивалентам.
Представьте себе задачу поиска взаимных друзей пользователей. Для формирования такого списка, на уровне кода, нужно сравнить два массива (мои друзья и друзья друга) и найти пересечение, то есть общих друзей. В данном случае массивы с друзьями это множества, а операция поиска общих элементов – пересечение (intersection).
Пересечение на руби выглядит так:
friends1 = ['igor', 'anna', 'nina', 'sergey']
friends2 = ['igor', 'petya', 'inna', 'anna']
# Выгялдит как побитовое И, но это пересечение
friends1 & friends2 # ["igor", "anna"]
# или
# friends1.intersection(friends2)
Такой оператор очень удобен своей естественностью. Сразу понятно о чем идет речь. Как и большинство других операторов в Ruby, мы имеем дело с вызовами методов:
friends.&(friends2)
Подобная схема позволяет не только переопределять их поведение, но и комбинировать операторы между собой:
friends2 = ['anna', 'ivan']
friends1 & friends2 & friends # ["anna"]
У множеств, с точки зрения математики, и массивов есть одно принципиальное отличие о котором нужно помнить. Во множествах каждый элемент представлен ровно один раз (то есть все элементы уникальны), в то время как в массивах такого ограничения не существует. Операции над множествами рассматривают массивы не как массивы, а именно как множества. Они удаляют дубли в результирующем массиве:
[1, 3, 4] & [1, 3, 3, 8] # [1, 3]
Объединение
Множество объединяющее в себе элементы исходных множеств.
[1, 3, 4] | [1, 3, 3, 8] # [1, 3, 4, 8]
Дополнение
Множество состоящее из элементов первого множества, за минусом элементов совпадающих со вторым множеством. Или по простому это разница между двумя множествами.
# 4 – единственный элемент из первого множества, которого нет во втором
[1, 3, 4] - [1, 3, 3, 8] # [4]
Задание
Иногда в программировании возникает задача поиска разницы между двумя наборами данных, такими как объекты. Например, при поиске различий в json файлах. Для этого даже существуют специальные сервисы, например, http://www.jsondiff.com/ (попробуйте нажать на ссылку sample data и затем кнопку Compare).
Реализуйте функцию, которая сравнивает два объекта и возвращает результат сравнения в виде объекта. Ключами результирующего объекта будут все ключи из двух входящих объектов, а значением строка с описанием отличий: added, deleted, changed или unchanged.
Возможные значения:
- added — ключ отсутствовал в первом объекте, но был добавлен во второй
- deleted — ключ был в первом объекте, но отсутствует во втором
- changed — ключ присутствовал и в первом и во втором объектах, но значения отличаются
- unchanged — ключ присутствовал и в первом и во втором объектах с одинаковыми значениями
gen_diff(
{ one: 'eon', two: 'two', four: true },
{ two: 'own', zero: 4, four: true }
);
# {
# one: 'deleted',
# two: 'changed',
# four: 'unchanged',
# zero: 'added'
# }