Array Practice

As some of you may know from previous threads im trying to practice
specific areas of ruby. One simple exercise i set myself was taking a
elements in an array such as

[1,2,3,1,2,2,4,3,2,1]

and then grouping them together and putting them in subarrays within an
array like this

[ [1,1,1], [2,2,2,2] , [3,3] ,[4] ]

Heres how i did it (im new to both programming and ruby)

def subpack(list)
uniqlist = Array.new
subpacklist = Array.new
list.sort!

uniqlist = list.uniq
uniqlist.each_index do |i|
rangeleft = list.index(uniqlist[i])
rangeright = list.rindex(uniqlist[i])
subpacklist << list.slice(rangeleft…rangeright)
end
subpacklist
end

WITHOUT GIVING ME YOUR SOLUTION IN FULL, how could i improve this…
i.e. give me some hints, the names of some methods but not the solution
as i want a go myself.

Adam A. wrote:
(…)

rangeleft = list.index(uniqlist[i])
rangeright = list.rindex(uniqlist[i])
subpacklist << list.slice(rangeleft..rangeright)

I like the index/rindex trick. I have actualy done a similar job, going
through a big logfile to see which users were most active.
I opted for an array of hashes, with the frequency as value.
My result would have been:
[{1=>3},{2=>4},{3=>2},{4=>1}]
Can adapt your code to do the same?

On Feb 6, 2008, at 6:20 PM, Adam A. wrote:

[ [1,1,1], [2,2,2,2] , [3,3] ,[4] ]
rangeleft = list.index(uniqlist[i])
as i want a go myself.
Think about how you might do it with a pencil…

  • write the values out in order “[ 1, 1, 1, 2, 2, 2, 2, 3, 3, 4 ]”
  • if the “next” value is different from the last value processed (and
    initially there is no last value), then start a new sub-array with
    this single value (my pencil would insert a ‘[’ between the ‘[’ and ‘1’)
  • …and if you’d already written a ‘[’, you have to then write “],[”
  • if the next value is the same, move your pencil (since it goes in
    the current sub-array)
  • when you run out of values, close the final subarray with ‘]’

It shouldn’t take much to think about how this turns into Ruby
(keeping in mind that Arrays are always finite so you don’t really
have to “write” the ‘]’)

-Rob

Rob B. http://agileconsultingllc.com
[email protected]

ahh cheers for that one as well rob…im on the case.

Well you know what, as i was thinking of a solution to this, hashes
popped into my head. I didnt know how they would be used but soemthing
whired and said you could probably do it with them. I always tend to shy
away from them but seeing as you laid down the challenge ill go away and
try and replicate your way. cheers!

In the meantime keep em coming!

Siep K. wrote:
(…)

[{1=>3},{2=>4},{3=>2},{4=>1}]
Can adapt your code to do the same?

Sorry. This should read
{1=>3, 2=>4, 3=>2, 4=>1}
Can you adapt your code to do the same?

Maybe you’d have to read up on hashes before you planned to. I’m
learning the same way as you do. Getting some grip on Fixnum, String,
Array, Hash, File and Date enabled me to write better scripts then I did
with any other scripting language.

Regards,

Siep

On Feb 6, 2008 5:20 PM, Adam A. [email protected] wrote:

rangeright = list.rindex(uniqlist[i])
subpacklist << list.slice(rangeleft..rangeright)

end
subpacklist
end

WITHOUT GIVING ME YOUR SOLUTION IN FULL, how could i improve this…
i.e. give me some hints, the names of some methods but not the solution
as i want a go myself.

My solution uses #uniq, #each, #<<, #select, and #==. Oh, and #[]

Todd

Adam A. wrote:

As some of you may know from previous threads im trying to practice
specific areas of ruby. One simple exercise i set myself was taking a
elements in an array such as

[1,2,3,1,2,2,4,3,2,1]

and then grouping them together and putting them in subarrays within an
array like this

[ [1,1,1], [2,2,2,2] , [3,3] ,[4] ]

Heres how i did it (im new to both programming and ruby)

def subpack(list)
uniqlist = Array.new
subpacklist = Array.new
list.sort!

uniqlist = list.uniq
uniqlist.each_index do |i|
rangeleft = list.index(uniqlist[i])
rangeright = list.rindex(uniqlist[i])
subpacklist << list.slice(rangeleft…rangeright)
end
subpacklist
end

WITHOUT GIVING ME YOUR SOLUTION IN FULL, how could i improve this…
i.e. give me some hints, the names of some methods but not the solution
as i want a go myself.

Another way would be to iterate over your original array and add each
number to a Hash as you go. A Hash keys will be one of the numbers,
and the corresponding value will be an array containing all of that
particular number.

You can create a new Hash so that when you access a non existent key in
a Hash an empty array will be returned. See the block form of
Hash.new().

Finally, you can create your final array from the hash values using
Hash#values.

On 2008-02-07 08:20 +0900 (Thu), Adam A. wrote:

[1,2,3,1,2,2,4,3,2,1]
and then grouping them together and putting them in subarrays within an
array like this
[ [1,1,1], [2,2,2,2] , [3,3] ,[4] ]

The Array#assoc method is your friend here.

If you have questions or comments on this, please Cc: me directly as
well as sending to the list. (This should happen automatically if the
list doesn’t wipe out my reply-to header.)

cjs

Anytime I want to “build up” something from an existing Enumerable
object (Array, etc.) in Ruby, I usually look to inject or collect; the
most elegant of the way I’ve come up with of doing exactly what you
want uses ==, *, uniq, collect, find_all, and size, and the function
body fits on a single line without semi-colons. (I’m not holding up
that it is a one-liner as a strength, just as a description.)

Curt S. wrote:

On 2008-02-07 08:20 +0900 (Thu), Adam A. wrote:

[1,2,3,1,2,2,4,3,2,1]
and then grouping them together and putting them in subarrays within an
array like this
[ [1,1,1], [2,2,2,2] , [3,3] ,[4] ]

The Array#assoc method is your friend here.

Really? Where’s the array containing arrays come from?

------------------------------------------------------------ Array#assoc
array.assoc(obj) -> an_array or nil

 Searches through an array whose elements are also arrays comparing
 obj with the first element of each contained array using obj.==.
 Returns the first contained array that matches (that is, the first
 associated array), or nil if no match is found. See also
 Array#rassoc.

Clifford H…

Oh, and uses [].

On 2008-02-07 11:15 +0900 (Thu), Christopher D. wrote:

…the most elegant of the way I’ve come up with of doing exactly
what you want uses ==, *, uniq, collect, find_all, and size, and the
function body fits on a single line without semi-colons.

Hm. My function uses: inject, assoc, and, or, <<, […]. The function
body fits easily on an 80 column line with one semicolon, if I shorten
the variable name “result” to “r”.

cjs

On Feb 6, 2008, at 8:30 PM, Clifford H. wrote:

Clifford H…
Array#assoc searches an existing array of arrays; it doesn’t build one.

[ [1,1,1], [2,2,2,2] , [3,3] ,[4] ].assoc(2) => [2,2,2,2]
[ [1,1,1], [2,2,2,2] , [3,3] ,[4] ].assoc(5) => nil

-Rob

Rob B. http://agileconsultingllc.com
[email protected]

On Feb 6, 2008, at 8:15 PM, Christopher D. wrote:

Anytime I want to “build up” something from an existing Enumerable
object (Array, etc.) in Ruby, I usually look to inject or collect; the
most elegant of the way I’ve come up with of doing exactly what you
want uses ==, *, uniq, collect, find_all, and size, and the function
body fits on a single line without semi-colons. (I’m not holding up
that it is a one-liner as a strength, just as a description.)

Ruby 1.9 lets you do it with a few less methods… (I’ll give it away
because I’m fairly sure the OP won’t be using 1.9). Of course, it only
works on immediate values…

[1,2,3,1,2,2,4,3,2,1].group_by(&:object_id).values

Cheers

Dave

one line (36 chars) with uniq, map, and select

On Feb 7, 2008 7:20 AM, Adam A. [email protected] wrote:

irb(main):002:0> a=[1,2,3,1,2,2,4,3,2,1]
=> [1, 2, 3, 1, 2, 2, 4, 3, 2, 1]
irb(main):003:0> a.group_by{|x|x}
=> {1=>[1, 1, 1], 2=>[2, 2, 2, 2], 3=>[3, 3], 4=>[4]}
irb(main):004:0> a.group_by{|x|x}.values
=> [[1, 1, 1], [2, 2, 2, 2], [3, 3], [4]]

ruby1.9 though. i’m threading on 1.9 since it is fast, i mean really
fast, even on windows :slight_smile:
kind regards -botp

On 2008-02-07 11:47 +0900 (Thu), Charles Snider wrote:

one line (36 chars) with uniq, map, and select

Note that, given the output specification, I wonder if it isn’t
important
that the input objects themselves be preserved in the output array. I
did
a test for that:

class AlwaysEqual
    def ==(o); true; end
    def hash; 0; end
end

def test_group_references
    a = AlwaysEqual.new
    b = AlwaysEqual.new
    r = group([a, b])
    assert_equal([[a, b]], r)
    assert_same(a, r[0][0])
    assert_same(b, r[0][1])
end

cjs

and with hashes

def subpack(passedlist)
hsh = Hash.new
subpacklist = []
#create a hsh of element frequency
passedlist.each do |element|
hsh[element] = hsh[element].to_i + 1
end

hsh.each do |key, value|
subgroup = Array.new
value.times {subgroup.push(key)}
subpacklist << subgroup
end
subpacklist
end

a few people have mentioned some pretty concise solutions involving
map/collect selete find_all etc

can someone give me an example of such a solution using the above.

thanks