8

I have two arrays, each containing any number of hashes with identical keys but differing values:

ArrayA = [{value: "abcd", value_length: 4, type: 0},{value: "abcdefgh", value_length: 8, type: 1}]
ArrayB = [{value: "ab", value_length: 2, type: 0},{value: "abc", value_length: 3, type: 1}]

Despite having any number, the number of hashes will always be equal.

How could I find the largest :value_length for every hash whose value is of a certain type?

For instance, the largest :value_length for a hash with a :type of 0 would be 4. The largest :value_length for a hash with a :type of 1 would be 8.

I just can't get my head around this problem.

the Tin Man
  • 158,662
  • 42
  • 215
  • 303
Starkers
  • 10,273
  • 21
  • 95
  • 158

4 Answers4

13

A simple way:

all = ArrayA + ArrayB # Add them together if you want to search both arrays.
all.select{|x| x[:type] == 0}
   .max_by{|x| x[:value_length]}

And if you wanna reuse it just create a function:

def find_max_of_my_array(arr,type)
  arr.select{|x| x[:type] == type}
     .max_by{|x| x[:value_length]}
end

p find_max_of_my_array(ArrayA, 0) # => {:value=>"abcd", :value_length=>4, :type=>0}
hirolau
  • 13,451
  • 8
  • 35
  • 47
  • 1
    This was causing me so much trouble. Perfect solution! (I know you shouldn't thank people on this site, but this really did help me out, and it's a concise and clear answer!) – Starkers Oct 08 '13 at 21:26
  • Thanks! Save my time a lot. – Hoang Le Jan 22 '15 at 03:44
0

I'm not totally sure I know what the output you want is, but try this. I assume the arrays are ordered so that ArrayA[x][:type] == ArrayB[x][:type] and that you are looking for the max between (ArrayA[x], ArrayB[x]) not the whole array. If that is not the case, then the other solutions that concat the two array first will work great.

filtered_by_type = ArrayA.zip(ArrayB).select{|x| x[0][:type] == type }
filtered_by_type.map {|a| a.max_by {|x| x[:value_length] } }
Alex.Bullard
  • 5,533
  • 2
  • 25
  • 32
0

Here's how I approached it: You're looking for the maximum of something, so the Array#max method will probably be useful. You want the actual value itself, not the containing hash, so that gives us some flexibility. Getting comfortable with the functional programming style helps here. In my mind, I can see how select, map, and max fit together. Here's my solution which, as specified, returns the number itself, the maximum value:

def largest_value_length(type, hashes)  
  # Taking it slowly
  right_type_hashes = hashes.select{|h| h[:type] == type}                                                 
  value_lengths     = right_type_hashes.map{|h| h[:value_length]}                                         
  maximum           = value_lengths.max                                                                   

  # Or, in one line                                                     
  #hashes.select{|h| h[:type] == type}.map{|h| h[:value_length]}.max                                       
end                                                                                                       

puts largest_value_length(1, ArrayA + ArrayB)                                                             

=> 8
Dogweather
  • 15,512
  • 17
  • 62
  • 81
0

You can also sort after filtering by type. That way you can get smallest, second largest etc.

all = ArrayA + ArrayB

all = all.select { |element| element[:type] == 1 }
        .sort_by { |k| k[:value_length] }.reverse

puts all[0][:value_length]
#8

puts all[all.length-1][:value_length]
#3
Linju
  • 335
  • 3
  • 9