I have an array of JSON object.
arr = [{'a'=> 1, 'b'=> 2, 'c'=> 3}, {'a'=> 4, 'b'=> 5,'c'=> 6}, {'a'=> 4, 'b'=> 5,'c'=> 6}]
But I want an new array which select 'a' and 'c' attributes only:
new_arr = [{'a'=> 1, 'c'=> 3}, {'a'=> 4,'c'=> 6}, {'a'=> 4,'c'=> 6}]
I try to use map but for 1 attribute only arr.map{|i| i['a']}.
What I am missing or any suggestion?
Make use of slice and pass the attributes you want to select
arr = [{'a'=> 1, 'b'=> 2, 'c'=> 3}, {'a'=> 4, 'b'=> 5,'c'=> 6}, {'a'=> 4, 'b'=> 5,'c'=> 6}]
arr.map{|a| a.slice('a', 'c')}
#=> [{"a"=>1, "c"=>3}, {"a"=>4, "c"=>6}, {"a"=>4, "c"=>6}]
You can use except
new_arr = arr.map{ |e| e.except('b') }
Since, there are already answers describing usage of slice and except, I would provide another way here:
arr.map{|h| {'a' => h['a'], 'c' => h['c'] } }
#=> [{"a"=>1, "c"=>3}, {"a"=>4, "c"=>6}, {"a"=>4, "c"=>6}]
Note that h here is a particular object of the array being iterated inside map, which is a Hash.
Bit more of a code to be typed though. You could use select as well.
Related
I am new to ruby on rails and trying to make a multidimensional hash from different arrays.
persons= [person1, person2, person3, person4]
projects= [project1, project2, project3]
issues= [1000, 10001, 1002, 1003, 1004,1005,1006,1007,1008,1009,1010]
issuetime = [1, 2 , 3, 4, 5]
I want a Hash like this:
hash = {person 1 =>{project1 => {1000, 1001, 1002 => {1,2,3}}}, person2 =>{project1 => {1003, 1004, 1005 => {3,4,5}}}}
I tried:
hash= {}
persons.each_with_index do [person,i]
if hash.has_key?(person)
hash[person] << projects[i]
else
hash[person] = [projects[i]]
end
end
This is working but it shows me only:
hash = {{person 1 =>{project1}}, {person2=>{project2}}}.
I want a multidimensional Hash if this is possible. I dont know how to access the next key + value to build a multidimensional hash.
Thanks for your help!
persons = ['person1', 'person2', 'person3']
projects = ['project1', 'project2', 'project3']
issues = [1000, 10001, 1002, 1003, 1004, 1005, 1006, 1007, 1008, 1009, 1010]
issuetimes = [1, 2 ,3, 4, 5, 6, 7, 8, 9]
persons.each_with_object({}).with_index do |(person, hsh), index|
hsh[person] = {
projects[index] => {
issues.slice!(0, 3) => issuetimes.slice!(0, 3)
}
}
end
This will give you. {"person1"=>{"project1"=>{[1000, 10001, 1002]=>[1, 2, 3]}}, "person2"=>{"project2"=>{[1003, 1004, 1005]=>[4, 5, 6]}}, "person3"=>{"project3"=>{[1006, 1007, 1008]=>[7, 8, 9]}}}
A couple of things to note about this question.
{1000, 1001, 1002 => {1,2,3}} is not a valid hash, as it will throw an error. However, you can do the following [1, 2, 3]=>[4, 5, 6]}, so my answer above assumes that is what you want to do.
My solution uses the destructive form of slice!, so note that the issues and issuetimes arrays will be changed from this solution. If you don't want that I would make duplicates of those arrays using the dup method.
On a somewhat related note, you might want to check out zip when it comes to creating hashes from arrays. Hash[persons.zip(projects)] // {"person1"=>"project1", "person2"=>"project2", "person3"=>"project3"}, which is not what you want here, but I thought I would mention it.
Ok so I have an array of 'winner ids' this array represents users who have won in the previous round of a tournament. I then have an array of objects called 'tournament participations', this represents all the users that have participated in the tournament (many to many relationship join table).
For each 'winner id' I want to iterate through the 'tournament participations' array and find the tournament participation with a user_id that matches the 'winner id', then push it into a new array called 'round participations'...
I have tried the code below but I always get returned the original 'winner_ids' array....
#challenges = Challenge.where(tournament_id: #tournament.id)
#winner_ids = #challenges.pluck(:winner_id)
#tournament_participations = #tournament.tournament_participations
#round_participations = []
#round_participations = #winner_ids.each do |winner_id|
#round_participation = #tournament_participations.where(user_id: winner_id)
#round_participations << #round_participation
end
each returns the enumerable it was called on; in this case, #winner_ids.each is returning #winner.ids. You don't need to assign the result of the iteration to #round_participations.
Also, check out the map method.
Use the map method, instead of .each.
The map method can be used to create a new array based on the original array, but with the values modified by the supplied block. See the below example.
In case of each method
irb(main):001:0> arr = [1, 2, 3, 4, 5]
=> [1, 2, 3, 4, 5]
irb(main):002:0> arr.each { |a| print a -= 10, " " }
-9 -8 -7 -6 -5
=> [1, 2, 3, 4, 5]
you can see after iterations it returned the original array. But in the case of map
irb(main):005:0> arr = [1, 2, 3, 4, 5]
=> [1, 2, 3, 4, 5]
irb(main):006:0> arr.map { |a| 2*a }
=> [2, 4, 6, 8, 10]
map can transform the contents of an array, meaning that it can perform an operation on each element in the array.
This question already has answers here:
Sorting an array based on an attribute that may be nil in some elements
(3 answers)
Closed 7 years ago.
Let's say I have an array of: [{one: 1, two: 2}, {one: 5, two: 6}] and I want to use sort_by something like:
[1] pry(main)> [{one: 1, two: 2}, {one: 5, two: 6}].sort_by{|x| [x[:one], x[:two]]}
However when I introduce nil for one of the values I get ArgumentError: comparison of Array with Array failed :
=> [{:one=>1, :two=>2}, {:one=>5, :two=>6}]
[2] pry(main)> [{one: 1, two: 2}, {one: nil, two: 6}].sort_by{|x| [x[:one], x[:two]]}
ArgumentError: comparison of Array with Array failed
How can I avoid this error?
Use this syntax,
starred.sort_by { |a| [a ? 1 : 0, a] }
When it has to compare two elements, it compares an arrays. When Ruby compares arrays (calls === method), it compares 1st element, and goes to the 2nd elements only if the 1st are equal. ? 1 : 0 guarantees, that we'll have Fixnum as 1st element, so it should be no error.
If you do ? 0 : 1, nil will appear at the end of array instead of beginning.
Here is an example:
irb> [2, 5, 1, nil, 7, 3, nil, nil, 4, 6].sort_by { |i| [i ? 1 : 0, i] }
=> [nil, nil, nil, 1, 2, 3, 4, 5, 6, 7]
Source.
I need to make sure the follower_id and followed_id are unique in an array which also includes a third number, called value. All are integers. It is the combination of follower_id and followed_id that needs to be unique not the individual numbers themselves. Here is what I have
Relationship.populate 1..20 do |relationship|
relationship.follower_id = (1..20)
relationship.followed_id = (1..20)
relationship.value = rand(1..5)
end
this would ensure that
1,3,5
1,3,5
2,3,5
1,2,5
would be
1,3,5
2,3,5
1,2,5
Assuming, that the order in pairs is not to be taken into account, and you want to eliminate triples, even having different values, here you go:
a = [[1,3,5], [3,1,5], [2,3,5], [2,3,6], [1,2,5]]
# to count [1,3,5] and [3,1,5] as similar
a.group_by { |(fd,fr,_)| [fd,fr].sort }.values.map &:first
# to count [1,3,5] and [3,1,5] as different
a.group_by { |(fd,fr,_)| [fd,fr] }.values.map &:first
#⇒ [[1,3,5], [3,1,5], [2,3,5], [1,2,5]]
a = [[1,3,5], [1,3,4], [3,1,2], [2,3,2], [2,3,1], [1,2,3]]
If the order of the first two elements of each element of a is important:
a.uniq { |e| e[0,2] }
#=> [[1, 3, 5], [3, 1, 2], [2, 3, 2], [1, 2, 3]]
If the order of the first two elements of each element of a is not important:
require 'set'
a.uniq { |e| Set.new e[0,2] }
#=> [[1, 3, 5], [2, 3, 2], [1, 2, 3]]
Perfect Uniqueness
Here's a solution assuming the order within the triples matters and you want each triple to be perfectly unique. Just use the uniq method on the Array class. It works like this:
[
[1,3,5],
[1,3,5],
[2,3,5],
[1,2,5]
].uniq
#=> [[1, 3, 5], [2, 3, 5], [1, 2, 5]]
Partial Uniqueness
If instead, you only care about the first two being unique, pass the uniq method a block that returns whatever subset you want to be unique. If you only want the first two elements of the triple and can discard duplicates even when the third element is unique, you can just pass it the range 0..1.
[
[1,3,5],
[1,3,5],
[2,3,5],
[1,2,5],
[1,2,6]
].uniq { |triple| triple[0..1] }
#=> [[1, 3, 5], [2, 3, 5], [1, 2, 5]]
Note that the last element, [1,2,6] was discarded even though it ended in 6 because it was considered a duplicate of [1,2,5]. This is because [1,2,5][0..1] #=> [1,2] and [1,2,6][0..1] #=> [1,2].
I'm coding a plugin in Google Sketchup with ruby and I faced a real problem while trying to permute two arrays that are present in an array all this depending on a user combination.
I have an array of arrays like [["1"],["lol"], ["so"]]
When we have a combination like this <[1,
2, 3] it's fine, it should stay the same : [["1"],["lol"], ["so"]]
But when we have a combination like this [2, 3, 1], the output should be : [["lol"], ["so"], ["1"]]
For [3,1,2] => [["so"], ["1"], ["lol"]]
...etc
EDIT
Sorry guys I forgot for the array I have a bit like : [["1, 2, 3"], ["lol1, lol2, lol3"], ["so1, so2, so3"]] so for the combination [2, 3, 1] the output should be : [["2, 3, 1"], ["lol2, lol3, lol1"], ["so2, so3, so1"]]
Thanks for helping me out.
You could use collect:
array = [["1"],["lol"], ["so"]]
indexes = [2, 1, 3]
indexes.collect {|i| array[i-1]} #=> [["lol"], ["1"], ["so"]]
If you set the indexes to be 0-based you could drop the -1
split and map can be used to turn your strings into values:
"1, 2, 3".split(",").map { |i| i.to_i} # [1, 2, 3]
You can then also split your strings
"lol2, lol3, lol1".split(/, /) #=> ["lol2", "lol3", "lol1"]
You should be able to put that together with the above to get what you want.
indexes = [2, 1, 3]
array = [["1"],["lol"], ["so"]]
result = indexes.map{|index| array[index-1] }
You should also take a look at active_enum
https://github.com/adzap/active_enum
You could do something like:
class YourClassName < ActiveEnum::Base
value [1] => ['1']
value [2] => ['lol']
value [3] => ['so']
end
a = [["1"], ["lol"], ["so"]]
index = [2, 1, 3]
index.collect {|i| a[i - 1]}
This outputs
[["lol"], ["1"], ["so"]]