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

      

+3


source to share


2 answers


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.

+2


source


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).

+2


source







All Articles