clojure sorting map values alphabetically by a keyword - sorting

How would I sort
{
{:name "d" :id 2}
{:name "f" :id 3}
{:name "a" :id 1}
{:name "z" :id 9}
}
Alphabetically by name? Like this:
{
{:name "a" :id 1}
{:name "d" :id 2}
{:name "f" :id 3}
{:name "z" :id 9}
}

When in doubt, be sure to look at the Clojure CheatSheet.
In this case just use sort-by
(def data
[{:name "d" :id 2}
{:name "f" :id 3}
{:name "a" :id 1}
{:name "z" :id 9}])
(sort-by :name data) =>
({:name "a", :id 1}
{:name "d", :id 2}
{:name "f", :id 3}
{:name "z", :id 9})
Note that I had to fix your data to use square brackets [...]

Related

Compare two arrays of hashes and return new object

I have two arrays of hashes.
burgers = [
{:id => 1, :name => "cheese burger"},
{:id => 2, :name => "royale"},
{:id => 3, :name => "big mac"},
{:id => 4, :name => "angus beef"}
]
eaten = [
{:burger_id => 1},
{:burger_id => 2}
]
I would like to return an array or uneaten burgers, where burgers[:id] does not equal eaten[:burger_id]. In burgers_not_eaten_method, I have the expected return value.
def burgers_not_eaten
#Not sure how to compare burger[:id] with eaten[:burger_id]
burgers.reject { |burger| burger[:id] == #eaten burger_id }
# Expected: [{:id => 3, :name => "big mac"},{:id => 4, :name => "angus beef"}]
end
You're close, to make it easy I'd snag all the "eaten" ids into an array, and check for inclusion in that array, like so:
BURGERS = [
{:id => 1, :name => "cheese burger"},
{:id => 2, :name => "royale"},
{:id => 3, :name => "big mac"},
{:id => 4, :name => "angus beef"}
]
EATEN = [
{:burger_id => 1},
{:burger_id => 2}
]
def burgers_not_eaten
eaten_ids = EATEN.map { |e| e[:burger_id] }
BURGERS.reject { |burger| eaten_ids.include?(burger[:id]) }
end
burgers_not_eaten
# => [{:id=>3, :name=>"big mac"}, {:id=>4, :name=>"angus beef"}]

Find keep duplicates in Ruby hashes

I have an array of hashes where I need to find and store matches based on one matching value between the hashes.
a = [{:id => 1, :name => "Jim", :email => "jim#jim.jim"},
{:id => 2, :name => "Paul", :email => "paul#paul.paul"},
{:id => 3, :name => "Tom", :email => "tom#tom.tom"},
{:id => 1, :name => "Jim", :email => "jim#jim.jim"},
{:id => 5, :name => "Tom", :email => "tom#tom.tom"},
{:id => 6, :name => "Jim", :email => "jim#jim.jim"}]
So I would want to return
b = [{:id => 1, :name => "Jim", :email => "jim#jim.jim"},
{:id => 3, :name => "Tom", :email => "tom#tom.tom"},
{:id => 5, :name => "Tom", :email => "tom#tom.tom"},
{:id => 6, :name => "Jim", :email => "jim#jim.jim"}]
Notes: I can sort the data (csv) by :name after the fact so they don't have to be nicely grouped, just accurate. Also it's not necessary two of the same, it could be 3 or 10 or more.
Also, the data is about 22,000 rows.
I tested this and it will do exactly what you want:
b = a.group_by { |h| h[:name] }.values.select { |a| a.size > 1 }.flatten
However, you might want to look at some of the intermediate objects produced in that calculation and see if those are more useful to you.

How to sort lines of a hash in descending order according to one of the key-value pairs in Ruby?

I have the following hash:
lines[0] = {"a" => dog, "b" => 32, "c" =>555, "d" => 100}
lines[1] = {"a" => cat, "b" => 34, "c" =>554, "d" => 4542}
lines[2] = {"a" => bird, "b" => 31, "c" =>532435, "d" => 23}
I would like to sort the hash by "b" in descending order so that I end up with:
lines[0] = {"a" => cat, "b" => 34, "c" =>554, "d" => 4542}
lines[1] = {"a" => dog, "b" => 32, "c" =>555, "d" => 100}
lines[2] = {"a" => bird, "b" => 31, "c" =>532435, "d" => 23}
What would be the best way to achieve that? Is there a method in Ruby that does this for you?
You seem to have a peculiar case where lines is NOT an array but a Hash, so you want to reassign values for each key based on value's order, for that first create array out of Hash, sort that, and that create a Hash based on new index e.g.
lines = {}
lines[0] = {"a" => :dog, "b" => 32, "c" =>555, "d" => 100}
lines[1] = {"a" => :cat, "b" => 34, "c" =>554, "d" => 4542}
lines[2] = {"a" => :bird, "b" => 31, "c" =>532435, "d" => 23}
require 'pp'
pp Hash[lines.map.sort_by {|k,v| -v["b"]}.map.with_index {|v, index| [index, v[1]]}]
output is:
{0=>{"a"=>:cat, "b"=>34, "c"=>554, "d"=>4542},
1=>{"a"=>:dog, "b"=>32, "c"=>555, "d"=>100},
2=>{"a"=>:bird, "b"=>31, "c"=>532435, "d"=>23}}
That said, why lines is a Hash? it could better be represented by an Array
lines.sort_by! {|hash| -hash["b"]}
You can do
lines.sort! { |a, b| b["b"] <=> a["b"] }

hash containing an array to array of hashes in ruby

I've read through quite a few of posts, but none seem to do just this, which is a bit tricky.
Say I have a hash that contains an array as one of its values.
hash = {
:a => 'one',
:arr => [
{:id => 'ten', :amount => 10, :b => 'two'},
{:id => 'twenty', :amount => 20, :b => 'two'},
{:id => 'apple', :amount => 7, :b => 'applesauce'}
],
:c => 3
}
I want to convert this to an array of hashes (which would be of the size of the contained array), as follows:
# => [
{:a => 'one', :id => 'ten', :amount => 10, :b => 'two', :c => 3},
{:a => 'one', :id => 'twenty', :amount => 20, :b => 'two', :c => 3},
{:a => 'one', :id => 'apple', :amount => 7, :b => 'applesauce', :c => 3}
]
The conversion should maintain whatever key/value pairs are inside and outside the array, and ideally I could pass in the key of the array to ask it perform the action:
flatten_hash_array(hash, :arr)
I realize that the Ruby flatten in the Array class is not what we need. Grasping for a verb! Any help would be appreciated.
This should do the job, barring validity checks.
def flatten_hash_array(hash, key)
hash[key].map {|entry| entry.merge(hash.reject {|k| k == key})}
end

ruby array includes an id

I currently want to iterate over an array of Objects (2 properties: id & name) and check if the array contains a specific Id
How would I do this?
Enumerable#detect is ok, but I think that Enumerable#any? (which returns a boolean), is strictly what you asked for:
xs = [{:id => 1, :name => 'a'}, {:id => 2, :name => 'b'}]
puts xs.any? {|x| x[:id] == 1} # true
puts xs.any? {|x| x[:id] == 5} # false
Try detect
a = [{:id => 1, :name => 'a'}, {:id => 2, :name => 'b'}]
puts a.detect {|x| x[:id] == 1}

Resources