Перебирать хеши, чтобы найти значения, предопределенные в массиве - PullRequest
0 голосов
/ 28 мая 2020

У меня есть массив с хешами:

test  = [
  {"type"=>1337, "age"=>12, "name"=>"Eric Johnson"},
  {"type"=>1338, "age"=>18, "name"=>"John Doe"},
  {"type"=>1339, "age"=>22, "name"=>"Carl Adley"},
  {"type"=>1340, "age"=>25, "name"=>"Anna Brent"}
]

Мне интересно получить все хеши, в которых ключ имени равен значению, которое можно найти в массиве:

get_hash_by_name = ["John Doe","Anna Brent"]

Что закончится следующим образом:

# test_sorted = would be:
# {"type"=>1338, "age"=>18, "name"=>"John Doe"}
# {"type"=>1340, "age"=>25, "name"=>"Anna Brent"}

Мне, вероятно, придется как-то повторить с test.each, но я все еще пытаюсь получить gr asp из Ruby. Рад всем помощи!

Ответы [ 2 ]

4 голосов
/ 28 мая 2020

Вот над чем можно подумать:

Итерация по массиву в поисках чего-то выполняется медленно, даже если это отсортированный массив. В компьютерных языках есть различные структуры, которые мы можем использовать для повышения скорости поиска, и Ruby Ha sh обычно является хорошей отправной точкой. Если массив похож на чтение из последовательного файла, Ha sh похож на чтение из файла с произвольным доступом, мы можем сразу перейти к нужной нам записи.

Начиная с вашего test массива- of-hashes:

test  = [
  {'type'=>1337, 'age'=>12, 'name'=>'Eric Johnson'},
  {'type'=>1338, 'age'=>18, 'name'=>'John Doe'},
  {'type'=>1339, 'age'=>22, 'name'=>'Carl Adley'},
  {'type'=>1340, 'age'=>25, 'name'=>'Anna Brent'},
  {'type'=>1341, 'age'=>13, 'name'=>'Eric Johnson'},
]

Обратите внимание, что я добавил дополнительную запись «Eri c Johnson». Я вернусь к этому позже.

Я бы создал ha sh, который сопоставил бы массив хэшей с обычным ha sh, где ключ каждой пары является уникальным значением. Пара ключ / значение 'type', похоже, подходит для этой потребности:

test_by_types = test.map { |h| [
  h['type'], h]
}.to_h
# => {1337=>{"type"=>1337, "age"=>12, "name"=>"Eric Johnson"},
#     1338=>{"type"=>1338, "age"=>18, "name"=>"John Doe"},
#     1339=>{"type"=>1339, "age"=>22, "name"=>"Carl Adley"},
#     1340=>{"type"=>1340, "age"=>25, "name"=>"Anna Brent"},
#     1341=>{"type"=>1341, "age"=>13, "name"=>"Eric Johnson"}}

Теперь test_by_types - это ha sh с использованием значения type для указания на исходный ha sh.

Если я создам аналогичный ha sh на основе имен, где каждое имя, уникальное или нет, указывает на значения type, я могу выполнять быстрый поиск:

test_by_names = test.each_with_object(
                  Hash.new { |h, k| h[k] = [] }
                ) { |e, h|
                    h[e['name']] << e['type']
                  }.to_h
# => {"Eric Johnson"=>[1337, 1341],
#     "John Doe"=>[1338],
#     "Carl Adley"=>[1339],
#     "Anna Brent"=>[1340]}

Обратите внимание, что «Eri c Johnson» указывает на две записи.

Теперь, вот как мы ищем вещи:

get_hash_by_name = ['John Doe', 'Anna Brent']

test_by_names.values_at(*get_hash_by_name).flatten
# => [1338, 1340]

За один быстрый поиск Ruby вернул совпадение types путем поиска имен.

Мы можем взять этот вывод и получить исходные хэши:

test_by_types.values_at(*test_by_names.values_at(*get_hash_by_name).flatten)
# => [{"type"=>1338, "age"=>18, "name"=>"John Doe"},
#     {"type"=>1340, "age"=>25, "name"=>"Anna Brent"}]

Поскольку это работает против хешей, это быстро. Хеши могут быть БОЛЬШИМИ, и они все равно будут работать очень быстро.

Вернуться к «Эри c Джонсон» ...

При работе с именами людей могут возникнуть конфликты имен, поэтому test_by_names допускает несколько значений type, поэтому с помощью одного поиска можно получить все совпадающие записи:

test_by_names.values_at('Eric Johnson').flatten
# => [1337, 1341]

test_by_types.values_at(*test_by_names.values_at('Eric Johnson').flatten)
# => [{"type"=>1337, "age"=>12, "name"=>"Eric Johnson"},
#     {"type"=>1341, "age"=>13, "name"=>"Eric Johnson"}]

Это будет много, если вы новинка Ruby, но документация Ruby охватывает все это, так что покопайтесь в документации классов Ha sh, Array и Enumerable .

Кроме того, *, также известный как «splat», разбивает элементы массива из включающего массива на отдельные параметры, подходящие для передачи в метод. Я не могу вспомнить, где это задокументировано.

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

Суть всего Дело в том, что действительно важно подумать о том, как вы собираетесь хранить свои данные, когда вы впервые вставляете их в свою программу. Сделайте это неправильно, и вы перепрыгнете через серьезные препятствия, пытаясь сделать с ним полезные вещи. Сделайте это правильно, и код и данные будут передаваться очень легко, и вы сможете легко массировать / извлекать / комбинировать данные.

Другими словами, массивы - это контейнеры, полезные для хранения вещей, к которым вы хотите получить доступ последовательно, например заданий, которые вы хотите распечатать, сайтов, к которым вам нужно получить доступ по порядку, файлов, которые вы хотите удалить, в определенном порядке c , но они ужасны, когда вы хотите искать и работать с записью случайным образом.

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

И поэтому я сделал свой комментарий выше, спрашивая, что вы пытались сделать sh в первую очередь. См. « В чем проблема XY? » и « XyProblem » для получения дополнительной информации по этому конкретному вопросу.

3 голосов
/ 28 мая 2020

Вы можете использовать select и include?, поэтому

test.select {|object| get_hash_by_name.include? object['name'] }

… должно сработать.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...