How to remove duplicate elements in a 2D array

Hi all,

I have a 2D array as follow:

arr=[

     [ 'a',1,2,3],
     ['b',4,5,6],
     ['c',3,2,1],
     ['a',1.3,2.2,3,3],
     ...
     ['a', 2,1,3],
   ...
   ['a',2.1,1.5,3]

]

As you can see there are several rows containing element 'a',
and the last row containing 'a'' is the lastest one. I wonder if it
is possible to return a new array which contains the latest row having
'a' ,
together with other rows.

Thanks,

Li

···

--
Posted via http://www.ruby-forum.com/.

result =
arr.each { |x| result = x if x[0] == 'a' }
result

?

···

On Fri, Sep 25, 2009 at 4:34 PM, Li Chen <chen_li3@yahoo.com> wrote:

Hi all,

I have a 2D array as follow:

arr=[

\[ &#39;a&#39;,1,2,3\],
\[&#39;b&#39;,4,5,6\],
\[&#39;c&#39;,3,2,1\],
\[&#39;a&#39;,1\.3,2\.2,3,3\],
\.\.\.
\[&#39;a&#39;, 2,1,3\],

...
['a',2.1,1.5,3]

]

As you can see there are several rows containing element 'a',
and the last row containing 'a'' is the lastest one. I wonder if it
is possible to return a new array which contains the latest row having
'a' ,
together with other rows.

--
Paul Smith
http://www.nomadicfun.co.uk

paul@pollyandpaul.co.uk

Something like this perhaps:

arr.collect{ |a| a.include?( 'a' ) ? a : nil }.compact

···

On Fri, Sep 25, 2009 at 10:34 AM, Li Chen <chen_li3@yahoo.com> wrote:

Hi all,

I have a 2D array as follow:

arr=[

\[ &#39;a&#39;,1,2,3\],
\[&#39;b&#39;,4,5,6\],
\[&#39;c&#39;,3,2,1\],
\[&#39;a&#39;,1\.3,2\.2,3,3\],
\.\.\.
\[&#39;a&#39;, 2,1,3\],

...
['a',2.1,1.5,3]

]

As you can see there are several rows containing element 'a',
and the last row containing 'a'' is the lastest one. I wonder if it
is possible to return a new array which contains the latest row having
'a' ,
together with other rows.

--
Greg Donald
http://destiney.com/

Morning Li,

Hi all,

I have a 2D array as follow:

arr=[

    [ 'a',1,2,3],
    ['b',4,5,6],
    ['c',3,2,1],
    ['a',1.3,2.2,3,3],
    ...
    ['a', 2,1,3],
  ...
  ['a',2.1,1.5,3]

]

As you can see there are several rows containing element 'a',
and the last row containing 'a'' is the lastest one. I wonder if it
is possible to return a new array which contains the latest row having
'a' ,
together with other rows.

This would do it (not sure if it's optimal or not)

seen =
arr.reverse.select{ |x|
  check = !(seen.include?(x[0]))

···

On Fri, Sep 25, 2009 at 8:34 AM, Li Chen <chen_li3@yahoo.com> wrote:

Thanks,

Li
--
Posted via http://www.ruby-forum.com/\.

Sorry about the last response - hit the wrong button.....

Hi all,

I have a 2D array as follow:

arr=[

    [ 'a',1,2,3],
    ['b',4,5,6],
    ['c',3,2,1],
    ['a',1.3,2.2,3,3],
    ...
    ['a', 2,1,3],
  ...
  ['a',2.1,1.5,3]

]

As you can see there are several rows containing element 'a',
and the last row containing 'a'' is the lastest one. I wonder if it
is possible to return a new array which contains the latest row having
'a' ,
together with other rows.

Lets try this again shall we....

seen = # this stores the first elements as we pass through them
#we reverse the array because you want the last elements to be the ones
returned
#select will add an element to the return value if the block is true
arr.reverse.select{ |x|
  check = !(seen.include?(x[0])) #we check to see if we've seen this first
element before
  seen << x[0] #add the first element to our "seen" list - we don't care if
it's in here multiple times
  check #the block equals the check value
}.reverse #since we reversed once we want to do so again to get the correct
order back

John

···

On Fri, Sep 25, 2009 at 8:34 AM, Li Chen <chen_li3@yahoo.com> wrote:

Thanks,

Li
--
Posted via http://www.ruby-forum.com/\.

I think you want an array with unique member. If the member is not
unique
then return the last occur of it.

arr=[[ 'a',1,2,3],
['b',4,5,6],
['c',3,2,1],
['a',1.3,2.2,3,3],
['a', 2,1,3],
['a',2.1,1.5,3]]

result = arr.inject({}){|x,y| x[y[0]]=y[1..-1]; x}.map(&:flatten)
p result

# [["a", 2.1, 1.5, 3], ["b", 4, 5, 6], ["c", 3, 2, 1]]

···

--
Posted via http://www.ruby-forum.com/.

The main idea is to use Hash and use the first letter ("a","b","c") as a
key. I do it with "inject" and David do it with "Hash[]"

I change your arr

arr=[[ 'a',1,2,3],
['b',4,5,6],
['c',3,2,1],
['a',1.3,2.2,3,3],
['a', 2,1,3],
['a',2.1,1.5,3]]

to a hash

hash={'a'=>[1,2,3],
'b'=>[4,5,6],
'c'=>[3,2,1],
'a'=>[1.3,2.2,3,3],
'a'=>[2,1,3],
'a'=>[2.1,1.5,3]}

You can see that key "a" does repeat 4 times in hash. So, the last one
will replace the first one automatically.

finally,

hash = {"a"=>[2.1, 1.5, 3], "b"=>[4, 5, 6], "c"=>[3, 2, 1]}

The method ".map(&:flatten)" is use to converse hash back to array.

···

--
Posted via http://www.ruby-forum.com/.

Here is another way.
It works with Ruby 1.8.6.

p arr.map{|x| x[0]}.uniq.map{|y| arr.reverse.detect{|z| z[0] == y}}

# OR if order is important,

···

On Sat, Sep 26, 2009 at 12:34 AM, Li Chen <chen_li3@yahoo.com> wrote:

Hi all,

I have a 2D array as follow:

arr=[

    [ 'a',1,2,3],
    ['b',4,5,6],
    ['c',3,2,1],
    ['a',1.3,2.2,3,3],
    ...
    ['a', 2,1,3],
  ...
  ['a',2.1,1.5,3]

]

As you can see there are several rows containing element 'a',
and the last row containing 'a'' is the lastest one. I wonder if it
is possible to return a new array which contains the latest row having
'a' ,
together with other rows.

Thanks,

Li
--
Posted via http://www.ruby-forum.com/\.

#

p arr.reverse.map{|x| x[0]}.uniq.reverse.map{|y|
arr.reverse.detect{|z| z[0] == y}}

Harry

--
A Look into Japanese Ruby List in English

Hi all,

I have a 2D array as follow:

arr=[

\[ &#39;a&#39;,1,2,3\],
\[&#39;b&#39;,4,5,6\],
\[&#39;c&#39;,3,2,1\],
\[&#39;a&#39;,1\.3,2\.2,3,3\],
\.\.\.
\[&#39;a&#39;, 2,1,3\],

...
['a',2.1,1.5,3]

]

As you can see there are several rows containing element 'a',
and the last row containing 'a'' is the lastest one. I wonder if it
is possible to return a new array which contains the latest row having
'a' ,
together with other rows.

result =
arr.each { |x| result = x if x[0] == 'a' }
result

?

Sorry, this only solves the "Last row containing a" part of the
problem. If you're intending to eliminate duplicates, then use that
first element as the key to a hash.

result = {}
arr.each{|x| result[x[0]] = x[1,x.length-1]}

?

···

On Fri, Sep 25, 2009 at 4:39 PM, Paul Smith <paul@pollyandpaul.co.uk> wrote:

On Fri, Sep 25, 2009 at 4:34 PM, Li Chen <chen_li3@yahoo.com> wrote:

--
Paul Smith
http://www.nomadicfun.co.uk

paul@pollyandpaul.co.uk

--
Paul Smith
http://www.nomadicfun.co.uk

paul@pollyandpaul.co.uk

Yes this is what I want. But can you explain the code line in a little
bit more?

Thanks,

Li

Thairuby ->a, b {a + b} wrote:

···

I think you want an array with unique member. If the member is not
unique
then return the last occur of it.

arr=[[ 'a',1,2,3],
['b',4,5,6],
['c',3,2,1],
['a',1.3,2.2,3,3],
['a', 2,1,3],
['a',2.1,1.5,3]]

result = arr.inject({}){|x,y| x[y[0]]=y[1..-1]; x}.map(&:flatten)
p result

# [["a", 2.1, 1.5, 3], ["b", 4, 5, 6], ["c", 3, 2, 1]]

--
Posted via http://www.ruby-forum.com/\.

Hi --

···

On Sat, 26 Sep 2009, Thairuby ->a, b {a + b} wrote:

I think you want an array with unique member. If the member is not
unique
then return the last occur of it.

arr=[[ 'a',1,2,3],
['b',4,5,6],
['c',3,2,1],
['a',1.3,2.2,3,3],
['a', 2,1,3],
['a',2.1,1.5,3]]

result = arr.inject({}){|x,y| x[y[0]]=y[1..-1]; x}.map(&:flatten)
p result

# [["a", 2.1, 1.5, 3], ["b", 4, 5, 6], ["c", 3, 2, 1]]

Another way, at least in 1.9:

   result = Hash[arr.map {|a| [a.first, a] }].values

David

--
David A. Black, Director
Ruby Power and Light, LLC (http://www.rubypal.com)
Ruby/Rails training, consulting, mentoring, code review
Book: The Well-Grounded Rubyist (http://www.manning.com/black2\)

Hi --

···

On Sat, 26 Sep 2009, Thairuby ->a, b {a + b} wrote:

I think you want an array with unique member. If the member is not
unique
then return the last occur of it.

arr=[[ 'a',1,2,3],
['b',4,5,6],
['c',3,2,1],
['a',1.3,2.2,3,3],
['a', 2,1,3],
['a',2.1,1.5,3]]

result = arr.inject({}){|x,y| x[y[0]]=y[1..-1]; x}.map(&:flatten)
p result

# [["a", 2.1, 1.5, 3], ["b", 4, 5, 6], ["c", 3, 2, 1]]

You could economize on intermediate objects and method calls like
this:

   result = arr.inject({}){|x,y| x[y[0]]=y; x}.values

That way, you don't take the first element out, so you don't have to
put it back.

David

--
David A. Black, Director
Ruby Power and Light, LLC (http://www.rubypal.com)
Ruby/Rails training, consulting, mentoring, code review
Book: The Well-Grounded Rubyist (http://www.manning.com/black2\)

Thairuby ->a, b {a + b} wrote:

The method ".map(&:flatten)" is use to converse hash back to array.

Thanks.

But I still have some doubts about this line:

result = arr.inject({}){|x,y| x[y[0]]=y[1..-1];
               x
              }.map(&:flatten)

1) When I look at #inject method, I notice it only takes either no
augument or
an augument with initial value. But in your code it takes a hash. It is
kind of new/strange to me.

2) Why do you write an x alone after this line x[y[0]]=y[1..-1]; ?

3) #map(&:flatten) doesn't work in my Ruby version(1.8.6). Which version
are you using? But I make some changes and it works.

result = arr.inject( { } ){|x,y| x[y[0]]=y[1..-1]; x}.to_a
r=result.collect { |row| row.flatten}

Li

···

--
Posted via http://www.ruby-forum.com/\.

I knew there was a a better way to do this:

arr.each{|x| result[x[0]] = x[1..-1]}

is a more succinct second line.

···

On Fri, Sep 25, 2009 at 4:52 PM, Paul Smith <paul@pollyandpaul.co.uk> wrote:

On Fri, Sep 25, 2009 at 4:39 PM, Paul Smith <paul@pollyandpaul.co.uk> wrote:

On Fri, Sep 25, 2009 at 4:34 PM, Li Chen <chen_li3@yahoo.com> wrote:

Hi all,

I have a 2D array as follow:

arr=[

\[ &#39;a&#39;,1,2,3\],
\[&#39;b&#39;,4,5,6\],
\[&#39;c&#39;,3,2,1\],
\[&#39;a&#39;,1\.3,2\.2,3,3\],
\.\.\.
\[&#39;a&#39;, 2,1,3\],

...
['a',2.1,1.5,3]

]

As you can see there are several rows containing element 'a',
and the last row containing 'a'' is the lastest one. I wonder if it
is possible to return a new array which contains the latest row having
'a' ,
together with other rows.

result =
arr.each { |x| result = x if x[0] == 'a' }
result

?

Sorry, this only solves the "Last row containing a" part of the
problem. If you're intending to eliminate duplicates, then use that
first element as the key to a hash.

result = {}
arr.each{|x| result[x[0]] = x[1,x.length-1]}

--
Paul Smith
http://www.nomadicfun.co.uk

paul@pollyandpaul.co.uk

Thairuby ->a, b {a + b} wrote:

The method ".map(&:flatten)" is use to converse hash back to array.

Thanks.

But I still have some doubts about this line:

result = arr.inject({}){|x,y| x[y[0]]=y[1..-1];
x
}.map(&:flatten)

1) When I look at #inject method, I notice it only takes either no
augument or
an augument with initial value. But in your code it takes a hash. It is
kind of new/strange to me.

It's giving it an empty hash as the initial value, nothing strange at all.

2) Why do you write an x alone after this line x[y[0]]=y[1..-1]; ?

So that the result of the block is the hash and not y[1..-1] which is
the value of the assignment.

3) #map(&:flatten) doesn't work in my Ruby version(1.8.6). Which version
are you using? But I make some changes and it works.

result = arr.inject( { } ){|x,y| x[y[0]]=y[1..-1]; x}.to_a
r=result.collect { |row| row.flatten}

I'm guessing that he's using either 1.8.7 or 1.9 both of which define
Symbol#to_proc which allows this, or perhaps he's using the
activesupport gem which is part of Rails and defines this as well.

I like David Black's alternative suggestion:

  result = arr.inject({}){|x,y| x[y[0]]=y; x}.values

Note that neither of these preserve the ordering of the rows retained
from the original array in Ruby 1.8.x, but if you're happy I guess
that's not a requirement.

···

On Sat, Sep 26, 2009 at 10:56 AM, Li Chen <chen_li3@yahoo.com> wrote:

--
Rick DeNatale

Blog: http://talklikeaduck.denhaven2.com/
Twitter: http://twitter.com/RickDeNatale
WWR: http://www.workingwithrails.com/person/9021-rick-denatale
LinkedIn: http://www.linkedin.com/in/rickdenatale

Thairuby ->a, b {a + b} wrote:

> The method ".map(&:flatten)" is use to converse hash back to array.

Thanks.

But I still have some doubts about this line:

result = arr.inject({}){|x,y| x[y[0]]=y[1..-1];ash.
x
}.map(&:flatten)

1) When I look at #inject method, I notice it only takes either no
augument or
an augument with initial value. But in your code it takes a hash. It is
kind of new/strange to me.

The argument passed to inject is the initial value. Thus, we just want
the routine to start off with an empty hash.

2) Why do you write an x alone after this line x[y[0]]=y[1..-1]; ?

The value of the first argument to the block passed to inject is set
to the return value of the block. In Ruby everything's an expression,
so the return value of a method or block is just that of the last
expression run.

3) #map(&:flatten) doesn't work in my Ruby version(1.8.6). Which version
are you using? But I make some changes and it works.

I don't have Ruby 1.8.6 installed and its been forever since I
remember using it last, so (works in 1.8.7 and up though) :\

Also, here's a rather nasty version that retains the order of the
initial array's elements, if that's important:

irb(main):050:0> arry = [['a', 1, 2, 3], ['b', 4, 5, 6], ['c', 3, 2,
1], ['a', 1.3, 2.2, 3, 3], ['a', 2, 1, 3], ['a', 2.1, 1.5, 3]]
=> [["a", 1, 2, 3], ["b", 4, 5, 6], ["c", 3, 2, 1], ["a", 1.3, 2.2, 3,
3], ["a", 2, 1, 3], ["a", 2.1, 1.5, 3]]
irb(main):051:0> arry.reverse.inject() {|r, e| r.unshift(e) if r.map
{|x| x.first if x.first == e.first}.compact.size == 0; r}
=> [["b", 4, 5, 6], ["c", 3, 2, 1], ["a", 2.1, 1.5, 3]]

···

On Sep 26, 10:56 am, Li Chen <chen_...@yahoo.com> wrote:

Hi --

···

On Sun, 27 Sep 2009, Rick DeNatale wrote:

I like David Black's alternative suggestion:

result = arr.inject({}){|x,y| x[y[0]]=y; x}.values

Note that neither of these preserve the ordering of the rows retained
from the original array in Ruby 1.8.x, but if you're happy I guess
that's not a requirement.

And in 1.9, you can do this:

   arr.map.with_object({}) {|e,h| h[e[0]] = e }.values

which gets rid of the need to force the accumulator to be the hash
every time through.

David

--
David A. Black, Director
Ruby Power and Light, LLC (http://www.rubypal.com)
Ruby/Rails training, consulting, mentoring, code review
Book: The Well-Grounded Rubyist (http://www.manning.com/black2\)

r.map {|x| x.first if x.first == e.first}.compact.size == 0

I'm an idiot, Ruby likes to call this pile of silliness "detect":

arry.reverse.inject() {|r, e| r.unshift(e) unless r.detect {|x|
x.first == e.first}; r}

Thank you all for the inputs.

Li

···

--
Posted via http://www.ruby-forum.com/.

Hi --

···

On Sun, 27 Sep 2009, pharrington wrote:

r.map {|x| x.first if x.first == e.first}.compact.size == 0

I'm an idiot, Ruby likes to call this pile of silliness "detect":

arry.reverse.inject() {|r, e| r.unshift(e) unless r.detect {|x|
x.first == e.first}; r}

Couldn't resist throwing in another 1.9-esque version:

   arr.group_by(&:first).map(&:last).map(&:last)

:slight_smile: Of course mapping to [-1][-1] would work too (and probably more
efficiently).

David

--
David A. Black, Director
Ruby Power and Light, LLC (http://www.rubypal.com)
Ruby/Rails training, consulting, mentoring, code review
Book: The Well-Grounded Rubyist (http://www.manning.com/black2\)