Print array values ββin sort list and ascending order
I ask you, your help. I have an array "values" that I want to sort by 2 conditions.
First condition: using the sort list defined in the "sortlist" array. Second condition: from smallest to largest.
With my current script, I was able to print the values ββin the correct order for the first condition (sort list), but I have no idea how to apply the second sort condition (smallest to largest).
ruby -e'
values = [ "Ghu_1","Prw_1","Prw_3","Prw_5","Vep_3","Hom_2","Vep_1","Hom_1","Prw_2","Vep_2","Prw_4" ]
sortlist = [ "Hom","Vep","Ghu","Prw" ]
sortlist.each{ |s|
values.each{ |v|
puts v if v.include?(s)
}
}'
Current Ouput # Desired output
Hom_2 # Hom_1
Hom_1 # Hom_2
Vep_3 # Vep_1
Vep_1 # Vep_2
Vep_2 # Vep_3
Ghu_1 # Ghu_1
Prw_1 # Prw_1
Prw_3 # Prw_2
Prw_5 # Prw_3
Prw_2 # Prw_4
Prw_4 # Prw_5
UPDATE
Thanks to Sebastian. Fine.
It almost worked, as I noticed that if the characters after the "_" are not numbers, the second sort is wrong. For example, below output is incorrect for Pwr_XXX values
ruby -e'
values = [ "Ghu_Klca","Prw_Rkdg","Prw_Ceteu","Prw_Eriir","Vep_Msas23","Hom_Ttgr5","Vep_Qsccas","Hom_Ftjh","Prw_jpolq","Vep_Szbqh","Prw_Lmnajh" ]
sortlist = [ "Hom","Vep","Ghu","Prw" ]
puts sortlist.flat_map{ |s|
values.select{ |v|
v if v.include?(s)
}.sort
}'
Second update
I mean the first sort is based on the sortlist array. The second sort in ascending order is based on the characters after "_". In this case, the firt letter for the Prw values ββis C, E, j, L and R. But the current output is C, E, L, R and j. So j is at the end and should be after L. I hope that makes sense.
Current output Expected output
Hom_Ftjh # Hom_Ftjh
Hom_Ttgr5 # Hom_Ttgr5
Vep_Msas23 # Vep_Msas23
Vep_Qsccas # Vep_Qsccas
Vep_Szbqh # Vep_Szbqh
Ghu_Klca # Ghu_Klca
Prw_Ceteu # Prw_Ceteu
Prw_Eriir # Prw_Eriir
Prw_Lmnajh # Prw_jpolq
Prw_Rkdg # Prw_Lmnajh
Prw_jpolq # Prw_Rkdg
source to share
By looking at your code, you can create an empty array, and then inside your iteration values.each
, to route each element to an empty array if that element includes an element fromsortlist
new_list = []
sortlist.each{ |s|
values.each{ |v|
new_list << v if v.include?(s)
}
}
Then use group_by
to group them by the first character:
p new_list.group_by{|e| e[0]}
# => {"H"=>["Hom_2", "Hom_1"], "V"=>["Vep_3", "Vep_1", "Vep_2"], "G"=>["Ghu_1"], "P"=>["Prw_1", "Prw_3", "Prw_5", "Prw_2", "Prw_4"]}
Then use flat_map
to get a "simple" array with all your values, but inside the iteration, sort each value for each key in the hash:
p new_list.group_by{|e| e[0]}.flat_map{|_,v| v.sort}
# => ["Hom_1", "Hom_2", "Vep_1", "Vep_2", "Vep_3", "Ghu_1", "Prw_1", "Prw_2", "Prw_3", "Prw_4", "Prw_5"]
Or a combination flat_map
, select
and sort_by
(second update):
values = [ "Ghu_Klca","Prw_Rkdg","Prw_Ceteu","Prw_Eriir","Vep_Msas23","Hom_Ttgr5","Vep_Qsccas","Hom_Ftjh","Prw_jpolq","Vep_Szbqh","Prw_Lmnajh" ]
sortlist = [ "Hom","Vep","Ghu","Prw" ]
p sortlist.flat_map{ |s|
values.select{ |v|
v if v.include?(s)
}.sort_by(&:downcase)
}
# => ["Hom_Ftjh", "Hom_Ttgr5", "Vep_Msas23", "Vep_Qsccas", "Vep_Szbqh", "Ghu_Klca", "Prw_Ceteu", "Prw_Eriir", "Prw_jpolq", "Prw_Lmnajh", "Prw_Rkdg"]
Use sort_by(&:downcase)
"ignore" when sorting.
source to share
values.sort_by { |val|
front, back = val.split('_')
[sortlist.index(front), back.downcase]
}
# => ["Hom_1", "Hom_2", "Vep_1", "Vep_2", "Vep_3", "Ghu_1", "Prw_1", "Prw_2", "Prw_3", "Prw_4", "Prw_5"]
# or
# => ["Hom_Ftjh", "Hom_Ttgr5", "Vep_Msas23", "Vep_Qsccas", "Vep_Szbqh", "Ghu_Klca", "Prw_Ceteu", "Prw_Eriir", "Prw_Lmnajh", "Prw_Rkdg", "Prw_jpolq"]
This works because arrays are compared by comparing the first element and then comparing the next element if the previous one is equal. I am currently comparing back
as if it were a string ( 10
preceded by 2
); if you need numeric ordering ( 2
preceded by 10
) use back.to_i
or back.to_f
(but that won't work with the second example).
source to share