Create variables depending on counter

Hi community,

First of all sorry for my english and I hope you get what I want to say.
As an example let us say I have an Array like this:

Car
Dog
Car
Car
Dog

What i want to do is I want to collect all Cars in a new Array and all
Dogs in a new Array, too.
So I need two new Arrays to do this. With Array.uniq.length I get the
number of my new Arrays I need.
Is there a way to implement this that the programme counts the uniq
elements in the array and creates variables depending on the counter.

So difficult to explain. I hope anyone can help me.

Thanks

Am 09.07.2013 17:13, schrieb stefan heinrich:

What i want to do is I want to collect all Cars in a new Array and all
Dogs in a new Array, too.
So I need two new Arrays to do this. With Array.uniq.length I get the
number of my new Arrays I need.
Is there a way to implement this that the programme counts the uniq
elements in the array and creates variables depending on the counter.

So difficult to explain. I hope anyone can help me.

I do not understand completely.
What should the two new arrays look like?

[‘Dog’, ‘Dog’], [‘Car’, ‘Car’, ‘Car’] ???

Doesn’t make too much sense to me…

Regards,
Marcus

Am 09.07.2013 17:13, schrieb stefan heinrich:

So I need two new Arrays to do this. With Array.uniq.length I get the
number of my new Arrays I need.
Is there a way to implement this that the programme counts the uniq
elements in the array and creates variables depending on the counter.

So difficult to explain. I hope anyone can help me.

Hi,

as I already said, it’s not completely clear to me what you want to do.
Anyway, I believe what you need is a hash :slight_smile:

Some use cases I could imagine:

Get a list of indices for all uniq elements:

array = [‘Car’, ‘Dog’, ‘Dog’, ‘Car’, ‘Dog’]
indices = Hash.new {|h,k| h[k] = [] }
array.each_with_index {|element, index| indices[element] << index }
indices

=> {“Car”=>[0, 3], “Dog”=>[1, 2, 4]}

indices[‘Car’]

=> [0, 3]

indices[‘Dog’]

=> [1, 2, 4]

Count the number of occurences:

occurences = Hash.new(0)
array.each {|element| occurences[element] += 1 }
occurences

=> {“Car”=>2, “Dog”=>3}

Regards,
Marcus

Yes as you mentioned it should look like

[‘Dog’, ‘Dog’] and
['Car, Car, Car].

If it doesn’t make sense for you i have to explain more.

I have a gui with a tablewidget.
Dog and Car are only row Headlines.

           Values

Dog | 12
Car | 14
Car | 67
Dog | 98
Dog | 32

I search for the Headlines and get the value from the current row. My
programme has to be intelligent and he should knows how many different
headlines I have. Depending on how many Variables I have my programme
should create new Array with only the values with the same headline.
Like this:

Arraydog = 12, 98, 32
Arraycar = 14, 67

Now I can combinate each value from the array with the values from the
other Arrays. The main thing is one value shouldn’t combine with a value
in the same class. I have this code:

a= arraydog, arraycar
combine = a.first.product(*a[1…-1]).map(&:join)

It works fine but only if I have two different Headlines. With more or
less headlines it doesn’t works…

I think you would be better served by using hashes instead of arrays for
something like this.

Am 09.07.2013 20:55, schrieb stefan heinrich:

            Values

Dog | 12
Car | 14
Car | 67
Dog | 98
Dog | 32
[…]
Depending on how many Variables I have my programme
should create new Array with only the values with the same headline.
Like this:

Arraydog = 12, 98, 32
Arraycar = 14, 67

You should use a hash with the headers as keys.

My examples can very easily be adapted to do exactly what you need.

Regards,
Marcus

On 2013-07-09, at 6:03 PM, stefan heinrich [email protected] wrote:

Hi marcus,

can u say how I have to use the Hash with the headers. I have tried
everything but it doesn’t work.

Thanks


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

Hi stefan,

One way you can build up an structure which mimics

Arraydog = 12, 98, 32
Arraycar = 14, 67

might be:

ratdog:~ mike$ pry
[1] pry(main)> records = Hash.new { |h, k| h[k] = [] }
=> {}
[2] pry(main)> records[:dog] << 12
=> [12]
[3] pry(main)> records[:dog] << 98
=> [12, 98]
[4] pry(main)> records[:car] << 14
=> [14]
[5] pry(main)> records[:car] << 67
=> [14, 67]
[6] pry(main)> records[:dog] << 32
=> [12, 98, 32]
[7] pry(main)> records
=> {:dog=>[12, 98, 32], :car=>[14, 67]}

Hope this helps,

Mike

Mike S. [email protected]
http://www.stok.ca/~mike/

The “`Stok’ disclaimers” apply.

Am 10.07.2013 00:03, schrieb stefan heinrich:

can u say how I have to use the Hash with the headers. I have tried
everything but it doesn’t work.

That’s not a very useful information…

You can take my first example:

Am 09.07.2013 17:47, schrieb [email protected]:

array = [‘Car’, ‘Dog’, ‘Dog’, ‘Car’, ‘Dog’]
indices = Hash.new {|h,k| h[k] = [] }
array.each_with_index {|element, index| indices[element] << index }
indices

=> {“Car”=>[0, 3], “Dog”=>[1, 2, 4]}

indices[‘Car’]

=> [0, 3]

indices[‘Dog’]

=> [1, 2, 4]

assuming your data is given as a 2-dimensional array:

data = [
[‘Dog’, 12],
[‘Car’, 14],
[‘Car’, 67],
[‘Dog’, 98],
[‘Dog’, 32]
]

then this would work (first, I create a hash with [] as the
default value, that’s the trickiest part of the whole thing):

values = Hash.new {|h,k| h[k] = [] }
data.each {|header, value| values[header] << value }
p values[‘Dog’] # [12, 98, 32]
p values[‘Car’] # [14, 67]

Depending on how your data is given, you need to modify
the second line.

I suggest you also look into the docs for the Hash class and
make heavy use of irb.

Regards,
Marcus

Hi marcus,

can u say how I have to use the Hash with the headers. I have tried
everything but it doesn’t work.

Thanks

Hi Robert and Marcus,

thanks for your help. Both methods are working very fine :D.
But now I have the Problem that I couldn’t combine the values.

The Result of my script looks like:

=> {“I OFF”=>[“34”], “E OFF”=>[“92”, “94”], “E ON”=>[“7f”],
“I ON”=>[“d9”, “cf”]}

I get always a nil when I want combine each value from one Array with
the other values from the other Arrays. I use

data.first.product(*data[1…-1]).map(&:join)

Can u say what the problem is now?

And if its possible can you explain how I can only combine I with E
values.
It doesnt make sense if I combine “I ON” with “I OFF” or “E ON” with “E
OFF”.

Thank u so much. I have been working for a few days but i dont find
anything.

On Wed, Jul 10, 2013 at 7:14 AM, [email protected] wrote:

=> [1, 2, 4]

]

then this would work (first, I create a hash with [] as the
default value, that’s the trickiest part of the whole thing):

values = Hash.new {|h,k| h[k] = [] }
data.each {|header, value| values[header] << value }

You can also use Enumerable#group_by:

irb(main):008:0> data.group_by {|s,i| s}
=> {“Dog”=>[[“Dog”, 12], [“Dog”, 98], [“Dog”, 32]], “Car”=>[[“Car”, 14],
[“Car”, 67]]}
irb(main):009:0> data.group_by {|s,i| s}.each {|k,v| v.map! {|s,i| i}}
=> {“Dog”=>[12, 98, 32], “Car”=>[14, 67]}

Depending on how your data is given, you need to modify
the second line.

I was going to ask in what structure the data is available. That bit of
information seems to be missing from the discussion.

I suggest you also look into the docs for the Hash class and

make heavy use of irb.

That’s excellent advice.

Kind regards

robert

Hi,

Why are the elements in the arrays not numbers? It looks like you
rather
want to work with numbers (Fixnum) here.

It’s not only numbers. In some cases there are strings.

Can you show us what’s in data? Please make sure to present complete
examples, otherwise it’s difficult to come up with answers - and to
follow
the discussion as well.

ok sorry…
my code to read out the tablewidget and create the array.

array = Array.new

for i in 0..rowCount - 1
  tmp = Array.new
  tmp << @tableWidget.item(i, 1).text.to_a
  tmp << @tableWidget.item(i, 0).text.to_a
  tmp = tmp[0] + tmp[1]

  array << tmp
end

array.group_by {|s,i| s}
array= array.group_by {|s,i| s}.each {|k,v| v.map! {|s,i| i}}

The 2d array looks like this after grouping

{“I OFF”=>[“a8”, “1e”], “E OFF”=>[“98”, “a0”], “Emphasized ON”=>[“db”],
“I ON”=>[“99”]}

It seems like after using grouping by it is not an array anymore. I use
array[0] and get a nil. How can I take only the values. I would like to
combine all combinations only I with E and E with I. It is not working.

irb(main):001:0> h = {“I OFF”=>[“34”], “E OFF”=>[“92”, “94”], “E
ON”=>[“7f”], “I ON”=>[“d9”, “cf”]}
=> {“I OFF”=>[“34”], “E OFF”=>[“92”, “94”], “E ON”=>[“7f”], “I
ON”=>[“d9”,
“cf”]}
irb(main):002:0> h.select {|k,| /^I/ =~ k}
=> {“I OFF”=>[“34”], “I ON”=>[“d9”, “cf”]}
irb(main):003:0> h.select {|k,| /^E/ =~ k}
=> {“E OFF”=>[“92”, “94”], “E ON”=>[“7f”]}

I have to try it now :D. Thanks

On Wed, Jul 10, 2013 at 4:21 PM, stefan heinrich
[email protected]wrote:

Hi Robert and Marcus,

thanks for your help. Both methods are working very fine :D.
But now I have the Problem that I couldn’t combine the values.

The Result of my script looks like:

=> {“I OFF”=>[“34”], “E OFF”=>[“92”, “94”], “E ON”=>[“7f”],
“I ON”=>[“d9”, “cf”]}

Why are the elements in the arrays not numbers? It looks like you
rather
want to work with numbers (Fixnum) here.

I get always a nil when I want combine each value from one Array with

the other values from the other Arrays. I use

data.first.product(*data[1…-1]).map(&:join)

Can u say what the problem is now?

Can you show us what’s in data? Please make sure to present complete
examples, otherwise it’s difficult to come up with answers - and to
follow
the discussion as well.

And if its possible can you explain how I can only combine I with E
values.
It doesnt make sense if I combine “I ON” with “I OFF” or “E ON” with “E
OFF”.

Well, just select e.g.

irb(main):001:0> h = {“I OFF”=>[“34”], “E OFF”=>[“92”, “94”], “E
ON”=>[“7f”], “I ON”=>[“d9”, “cf”]}
=> {“I OFF”=>[“34”], “E OFF”=>[“92”, “94”], “E ON”=>[“7f”], “I
ON”=>[“d9”,
“cf”]}
irb(main):002:0> h.select {|k,| /^I/ =~ k}
=> {“I OFF”=>[“34”], “I ON”=>[“d9”, “cf”]}
irb(main):003:0> h.select {|k,| /^E/ =~ k}
=> {“E OFF”=>[“92”, “94”], “E ON”=>[“7f”]}

Kind regards

robert

Well done :D…

I select the E with I and I with E like the following code. The
variables possible…possible3 are arrays.

possible << array.select {|k,| /^I ON/ =~ k} <<
array.select {|k,| /^E OFF/ =~ k}

possible1 << array.select {|k,| /^I ON/ =~ k} <<
array.select {|k,| /^E ON/ =~ k}

possible2 << array.select {|k,| /^I OFF/ =~ k} <<
array.select {|k,| /^E OFF/ =~ k}

possible3 << array.select {|k,| /^I OFF/ =~ k} <<
array.select {|k,| /^E ON/ =~ k}

One example of the possible combinations looks like:

[[[“I OFF”, [“10”, “e6”]]],
[[“E ON”, [“1f”, “e9”]]]]

The last step before i have finished is :smiley: that I would combine the
values.
I would like to have

10 1f
10 e9
e6 1f
e6 e9
1f 10
e9 10
1f e6
e9 e6

Is it possible to do it?

Am 11.07.2013 09:34, schrieb stefan heinrich:

   array << tmp

It seems like after using grouping by it is not an array anymore.
Yes indeed, as mentioned several times in the previous posts, we are
talking about a Hash of key-value pairs (where the values in this
case are arrays). And I already demonstrated in my examples how you
can access the stored arrays separately.

A reminder:

data = {“I OFF”=>[“a8”, “1e”], “E OFF”=>[“98”, “a0”], “Emphasized
ON”=>[“db”], “I ON”=>[“99”]}
p data[‘I OFF’] # => [“a8”, “1e”]

Also, I would like to repeat myself:

I suggest you also look into the docs for the Hash class and
make heavy use of irb.

And: Try to figure out what happens in the code examples that
people provide here.

Regards,
Marcus

Ok i got it. Thank you so much.

One more question.
Is it better if I work here with symbols instead of strings like I ON
etc…

Best regards

On Thu, Jul 11, 2013 at 9:34 AM, stefan heinrich
[email protected]wrote:

examples, otherwise it’s difficult to come up with answers - and to
tmp << @tableWidget.item(i, 1).text.to_a
tmp << @tableWidget.item(i, 0).text.to_a
tmp = tmp[0] + tmp[1]

  array << tmp
end

You can make your life a tad easier by not creating all those one
element
arrays with the #to_a call:

array = row_count.times.map do |i|
[1, 0].map! {|idx| @table_widget.item(i, idx).text}
end

Note the different spelling: in Ruby we use CamelCase only for classes
and
modules and snake_case for the rest.

array.group_by {|s,i| s}

This line does nothing. More precisely: it creates a Hash and then
immediately forgets it.

Reading the documentation sometimes really helps. :slight_smile:
http://www.ruby-doc.org/core-1.9.3/Enumerable.html#method-i-group_by

Cheers

robert

Hi,

It depends. Where do you get the data from? Is it a fixed set of
values?
etc.

ok, give me a try to explain. Lets take a look in the Hash

{“I OFF”=>[“a8”, “1e”], “E OFF”=>[“98”, “a0”], “E ON”=>[“db”],
“I ON”=>[“99”]}

The values “a8”, “1e”, “98” etc. are random generated values. There are
not fixed but they have an interval. Depending on the value if the LSB =
1 it is an ON and LSB = 0 it is a OFF. So normally we can say without
looking to the syntax

def value_?even(value)
return :E_ON if value & 0x01
return :E_OFF
end

But for a ruby newbie it is very difficult and confusing to understand
symbols in ruby. I have read so much articles and looked for example to
get it. But I think I need more time to understand symbols.

Now what do you suggest me, is it possible to implement this like I
explained?

On Fri, Jul 12, 2013 at 12:27 AM, stefan heinrich
[email protected]wrote:

One more question.
Is it better if I work here with symbols instead of strings like I ON
etc…

It depends. Where do you get the data from? Is it a fixed set of
values?
etc.

Kind regards

robert

On Fri, Jul 12, 2013 at 9:23 AM, stefan heinrich
[email protected]wrote:

It depends. Where do you get the data from? Is it a fixed set of
values? etc.

ok, give me a try to explain. Lets take a look in the Hash

I would prefer to look at the input data and see the larger picture.

return :E_OFF

end

Actually, to me it seems there are two values encoded in those Strings
you
have above: one is either “I” or “E” and another one is “ON” or “OFF”.
For
me that means a much more appropriate way to store it would be an
instance
with two attributes. You can easily have that with a Struct:

NameOfYourData = Struct.new :whatever_that_means, :enabled do
def self.from_string(s)
raise ArgumentError, “Invalid input: #{s}” unless
/\A(\w+)\s+(O(?:N|OFF))\z/ =~ s
new($1, $2 == “ON”)
end
end

irb(main):007:0> x = NameOfYourData.from_string “E ON”
=> #<struct NameOfYourData whatever_that_means=“E”, enabled=true>
irb(main):008:0> x.enabled
=> true
irb(main):009:0> x.whatever_that_means
=> “E”

Of course you would pick more meaningful names.

But for a ruby newbie it is very difficult and confusing to understand

symbols in ruby. I have read so much articles and looked for example to
get it. But I think I need more time to understand symbols.

It’s fairly easy when to use Symbols: you do that if the set of values
is
restricted. In other programming languages you would often use an enum
for
that (i.e. a type with a fixed set of values).

Now what do you suggest me, is it possible to implement this like I
explained?

As I said: without seeing the big picture and understanding what all
this
is about and what those different strings represent it’s not possible to
come up with good advice. We would need to know

  • what the input data looks like
  • what it means
  • what you want to do with it
  • what the whole purpose of the exercise is

Cheers

robert