vikas95prasad
vikas95prasad

Reputation: 1332

How to pull ids from array of hashes on ruby?

Given:

data = [
  {"id"=>nil, "votable_id"=>1150, "user_ids"=>"1120,1119,1118,1117,1116,1115,1114,1113,1112,1111,1110,1109,1108,1107"},
  {"id"=>nil, "votable_id"=>1151, "user_ids"=>"1120,1119,1118,1117,1116,1115,1114,1113,1112,1111,1110,1109,1108,1107"}
]

I wish to return an array of all unique representations of integers in the strings g["user_ids"], taken over all hashes g that are elements of data; namely,

["1120", "1119", "1118", "1117", "1116", "1115", "1114",
 "1113", "1112", "1111", "1110", "1109", "1108", "1107"]

Upvotes: 0

Views: 854

Answers (3)

KARASZI István
KARASZI István

Reputation: 31467

To get the unique ids:

unique_ids = data.flat_map { |d| d['user_ids'].split(',') }.uniq
  1. Enumerable#flat_map walks through the Array and concatenate the results provided in the code block.
  2. String#split divides the string by the delimiter into an Array.
  3. Array#uniq removes the duplicates.

Upvotes: 2

Cary Swoveland
Cary Swoveland

Reputation: 110675

data.reduce('') { |s,h| s + h['user_ids'] + ',' }.scan(/\d+/).uniq
  #=> ["1120", "1119", "1118", "1117", "1116", "1115", "1114", "1113",
  #    "1112", "1111", "1110", "1109", "1108", "1107"] 

The steps are as follows.

str = data.reduce('') { |s,h| s + h['user_ids'] + ',' }
  => "1120,1119,...1107,1120,1119,...1107," 
arr = str.scan(/\d+/)
  #=> ["1120", "1119", "1118", "1117", "1116", "1115", "1114", "1113",
  #    "1112", "1111", "1110", "1109", "1108", "1107", "1120", "1119",
  #    "1118", "1117", "1116", "1115", "1114", "1113", "1112", "1111",
  #    "1110", "1109", "1108", "1107"]
arr.uniq
  #=> ["1120", "1119", "1118", "1117", "1116", "1115", "1114", "1113",
  #    "1112", "1111", "1110", "1109", "1108", "1107"]

A problem with this approach is that the intermediate array arr can be quite large if data contains many elements (hashes) and for each element h, h['user_ids'].split(',') contains many elements. One way around that is to build a set, which of course contains unique elements, and then convert that set to an array at the end.

require 'set'

data.each_with_object(Set.new) { |h,set|
  h["user_ids"].split(',').each { |s| set << s } }.to_a
  #=> ["1120", "1119", "1118", "1117", "1116", "1115", "1114",
  #    "1113", "1112", "1111", "1110", "1109", "1108", "1107"]

See Set::new, Set#<< and Set#to_a.

Note that the array returned here contains the same elements as the array returned earlier, but in a different order. I assume that is no import.

Upvotes: 0

demir
demir

Reputation: 4709

If you use Rails, try this:

data.pluck('user_ids').join(',').split(',').uniq

If you don't use Rails:

data.map{ |d| d.dig('user_ids') }.join(',').split(',').uniq

Result:

#=> [
#     "1120", "1119", "1118", "1117", "1116", "1115", "1114",
#     "1113", "1112", "1111", "1110", "1109", "1108", "1107"
#   ]

Upvotes: 2

Related Questions