Bil_K
1
Hi,

I’m looking for an elegant way to do the following:

Given an sorted array of (X,Y) pairs where Y is strictly

increasing, i.e., no repeated Ys.

Compact pairs with repeated Xs, keeping the pair with

the highest Y value.

E.g.,

require ‘test/unit’

class TestConsolidation < Test::Unit::TestCase

def test_should_remove_repeated_Xs_but_save_one_with_highest_Y

initial = [ [ 1, 12 ], [ 3, 15 ], [ 3, 17 ], [ 3, 22 ], [ 7, 45 ]

]

desired = [ [ 1, 12 ], [ 3, 22 ], [ 7, 45 ] ]

assert_equal desired, initial.consolidate

end

end

class Array

def consolidate

# Too embarrassed to show current hack.

end

end

My least surprise inclination had me researching #uniq and #compact

to see if they took a block like #sort.

Thanks,

Bil_K
2
2008/1/7, Bil K. [email protected]:

I’m looking for an elegant way to do the following:

(…)

Bil, this makes the test pass:

class Array

def consolidate

Hash[*flatten].sort

end

end

Regards,

Pit

Bil_K
3
2008/1/7, Bil K. [email protected]:

E.g.,

class Array

def consolidate

# Too embarrassed to show current hack.

end

end

My least surprise inclination had me researching #uniq and #compact

to see if they took a block like #sort.

This is easy with #inject:

ar.inject([]) do |res, (x,y)|

if res.empty? || res.last[0] != x

res << [x,y]

else

res.last[1] = y

end

res

end

Cheers

robert

Bil_K
4
Pit C. wrote:

end

That certainly is elegant!

Maybe Bil wanted to preserve the monotonicity?

class Array

def consolidate

Hash[*flatten].sort_by {|x,y| y}

end

end

p [ [5,1] , [3,2] ].consolidate # ==> [[5, 1], [3, 2]]

Bil_K
5
On Jan 7, 10:45 am, Robert K. [email protected] wrote:

This is easy with #inject:

Hey, thanks everyone for the help!

I would have replied sooner, but my USENET feed dropped your replies

and I only now thought to look at groups.google.com.

Thanks again,

Bil_K
6
A more general solution:

require ‘set’

class Array

def uniq(&blk)

blk ||= lambda {|x| x}

already_seen = Set.new

uniq_array = []

self.each_with_index do |value, i|

x = blk.call(value)

unless already_seen.include? x

already_seen << x

uniq_array << value

end

end

uniq_array

end

end

and

class Array

def consolidate

reverse.uniq {|a| a.first}.reverse

end

end

Of course, the value that you keep for uniq is kinda arbitrary.

Dan