1

Say I'm given a string array, each string has a corresponding weight. So for example:

str_arr = ["james", "blake", "rob"]
weights = [4, 7, 1]

str_arr[i] corresponds to weights[i].

How would I go about sorting str_arr in ascending order with respect to weights? For example:

(after sorting) weights would be [1, 4, 7] which corresponds to str_arr = ["rob", "james", "blake"]

How do I get ["rob", "james", "blake"]?

Most sorting comparators deal with modifying the way the sorting on the current array works, and I looked into sorting with respect to the existing order of a different array--but I'm not sure how to sort the integer array and simultaneously do the same with the str_arr based on the output of the integer array...Is there a Rubyist way of doing this?

1
  • The Ruby way would be using a Hash instead of arrays {james: 4, blake: 7, ..} , sort on the weight value and use the the .keys method to have your array Commented Mar 17, 2017 at 23:20

4 Answers 4

2

You could use sort_by and with_index:

str_arr.sort_by.with_index { |_, i| weights[i] }
#=> ["rob", "james", "blake"]
Sign up to request clarification or add additional context in comments.

1 Comment

I've seen it (used at least once by @ArupRakshit, if memory serves) and was trying to remember it... Yes, the way to go.
1

You can do the following with parallel assignment:

str_arr, weights = str_arr.zip(weights).sort_by(&:last).transpose
#=> [["rob", "james", "blake"], [1, 4, 7]]

str_arr #=> ["rob", "james", "blake"] 
weights #=> [1, 4, 7]

Key methods: Array#zip, Enumerable#sort_by and Array#transpose.

3 Comments

This wouldn't work in the case that one of the weights was missing, correct?
Reverse the order, and you don't need sort_by : weights.zip(str_arr).sort.transpose
@Sunny not sure what you mean. How would an array with a missing weight look?
1
str_arr.values_at(*weights.size.times.sort_by { |i| weights[i] })
  #=> ["rob", "james", "blake"]

The two steps are as follows.

a = weights.size.times.sort_by { |i| weights[i] }
  #=> [2, 0, 1]
str_arr.values_at(*a)
  #=> ["rob", "james", "blake"]

See Array#values_at and Enumerable#sort_by.

1 Comment

O(n*log(n)) is boring. Here's a nice O(n!) solution : str_arr.permutation.to_a[weights.permutation.to_a.index(weights.sort)] ;)
1

If you have two arrays that are 100% linked to each other, you should use a Hash :

str_arr = ["james", "blake", "rob"]
weights = [4, 7, 1]

weights = str_arr.zip(weights).to_h
# {"james"=>4, "blake"=>7, "rob"=>1}

You can just sort_by value then :

str_arr = ["james", "blake", "rob"]
weights = [4, 7, 1]

weights = str_arr.zip(weights).to_h

p weights.sort_by{|k, v| v}.map(&:first)
#=> ["rob", "james", "blake"]

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.