Question about multi-demension hash initialization

Team,
Is there a quick (perhaps one liner) way to initialize the following hashes
into just one hash?

def xwing(ia)

p ia

puts " "
p @xwing

   r1 = {"1" => 0, "2" => 0, "3" => 0, "4" => 0, "5" => 0, "6" => 0, "7" =>
0, "8" => 0, "9" => 0}
   r2 = {"1" => 0, "2" => 0, "3" => 0, "4" => 0, "5" => 0, "6" => 0, "7" =>
0, "8" => 0, "9" => 0}
   r3 = {"1" => 0, "2" => 0, "3" => 0, "4" => 0, "5" => 0, "6" => 0, "7" =>
0, "8" => 0, "9" => 0}
   r4 = {"1" => 0, "2" => 0, "3" => 0, "4" => 0, "5" => 0, "6" => 0, "7" =>
0, "8" => 0, "9" => 0}
   r5 = {"1" => 0, "2" => 0, "3" => 0, "4" => 0, "5" => 0, "6" => 0, "7" =>
0, "8" => 0, "9" => 0}
   r6 = {"1" => 0, "2" => 0, "3" => 0, "4" => 0, "5" => 0, "6" => 0, "7" =>
0, "8" => 0, "9" => 0}
   r7 = {"1" => 0, "2" => 0, "3" => 0, "4" => 0, "5" => 0, "6" => 0, "7" =>
0, "8" => 0, "9" => 0}
   r8 = {"1" => 0, "2" => 0, "3" => 0, "4" => 0, "5" => 0, "6" => 0, "7" =>
0, "8" => 0, "9" => 0}
   r9 = {"1" => 0, "2" => 0, "3" => 0, "4" => 0, "5" => 0, "6" => 0, "7" =>
0, "8" => 0, "9" => 0}

end

(0..8).each do |r|
xwing(@xwing[[r][0]]) # @xwing is defined previously
end

Actually, I wanted just one hash, @frequency, but I did not know how to do
it.

Thank you

Ruby student

Err, what? You know how to create nine hashes but you do not know how to create one? I'm suspecting that there is something missing from your posting.

Maybe you wanted something like this:

irb(main):004:0> require 'pp'
=> true
irb(main):005:0> pp Array.new(9) { Hash[*(1..9).map {|i|[i.to_s,0]}.flatten] }
[{"6"=>0, "7"=>0, "8"=>0, "9"=>0, "1"=>0, "2"=>0, "3"=>0, "4"=>0, "5"=>0},
  {"6"=>0, "7"=>0, "8"=>0, "9"=>0, "1"=>0, "2"=>0, "3"=>0, "4"=>0, "5"=>0},
  {"6"=>0, "7"=>0, "8"=>0, "9"=>0, "1"=>0, "2"=>0, "3"=>0, "4"=>0, "5"=>0}]
=> nil
irb(main):006:0>

However, given the structure of your Hashes I wonder why you do not want to use Arrays instead. E.g.

irb(main):001:0> pp Array.new(9) { Array.new(9, 0) }
[[0, 0, 0, 0, 0, 0, 0, 0, 0],
  [0, 0, 0, 0, 0, 0, 0, 0, 0],
  [0, 0, 0, 0, 0, 0, 0, 0, 0]]
=> nil

Or even use a Matrix.

irb(main):006:0> require 'matrix'
=> true
irb(main):007:0> pp Matrix.zero 9
Matrix[[0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0
], [0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0], [
0, 0, 0, 0, 0, 0, 0, 0, 0]]
=> nil
irb(main):008:0> pp Matrix.zero(9).to_a
[[0, 0, 0, 0, 0, 0, 0, 0, 0],
  [0, 0, 0, 0, 0, 0, 0, 0, 0],
  [0, 0, 0, 0, 0, 0, 0, 0, 0]]
=> nil
irb(main):009:0>

Kind regards

  robert

···

On 19.09.2008 20:21, Ruby Student wrote:

[Note: parts of this message were removed to make it a legal post.]

Team,
Is there a quick (perhaps one liner) way to initialize the following hashes
into just one hash?

def xwing(ia)

p ia

puts " "
p @xwing

   r1 = {"1" => 0, "2" => 0, "3" => 0, "4" => 0, "5" => 0, "6" => 0, "7" =>
0, "8" => 0, "9" => 0}
   r2 = {"1" => 0, "2" => 0, "3" => 0, "4" => 0, "5" => 0, "6" => 0, "7" =>
0, "8" => 0, "9" => 0}
   r3 = {"1" => 0, "2" => 0, "3" => 0, "4" => 0, "5" => 0, "6" => 0, "7" =>
0, "8" => 0, "9" => 0}
   r4 = {"1" => 0, "2" => 0, "3" => 0, "4" => 0, "5" => 0, "6" => 0, "7" =>
0, "8" => 0, "9" => 0}
   r5 = {"1" => 0, "2" => 0, "3" => 0, "4" => 0, "5" => 0, "6" => 0, "7" =>
0, "8" => 0, "9" => 0}
   r6 = {"1" => 0, "2" => 0, "3" => 0, "4" => 0, "5" => 0, "6" => 0, "7" =>
0, "8" => 0, "9" => 0}
   r7 = {"1" => 0, "2" => 0, "3" => 0, "4" => 0, "5" => 0, "6" => 0, "7" =>
0, "8" => 0, "9" => 0}
   r8 = {"1" => 0, "2" => 0, "3" => 0, "4" => 0, "5" => 0, "6" => 0, "7" =>
0, "8" => 0, "9" => 0}
   r9 = {"1" => 0, "2" => 0, "3" => 0, "4" => 0, "5" => 0, "6" => 0, "7" =>
0, "8" => 0, "9" => 0}

end

(0..8).each do |r|
xwing(@xwing[[r][0]]) # @xwing is defined previously
end

Actually, I wanted just one hash, @frequency, but I did not know how to do
it.

First, thank you for your help and sample code.

What I need to do is to pass an integer compose of minimum 2 digits and
maximum of 8 and count the how many time a digit appears.
For example, I have a multidimensional array (9x9), which I then take each
row and each column at a time.

For instance, the following are two rows extracted from the 9x9 array:

r1 = [345, 8, 459, 125679, 123, 45679, 379, 679, 79]
r8 = [9, 4, 6789, 356, 1, 357, 2356, 257, 67]

So, for row r1:
1s = 2, 2s = 2, 3s = 3, 4s = 3, 5s = 4, 6s = 3, 7s = 5, 8s = 1, 9s = 6

The same reasoning follows for r8.
So the 9x9 hash represents the 9x9 array for Sudoku, but instead of
representing a Sudoku element, the key = the number while the value is the
count (frequency) of that key.
I am not sure if I am explaining myself clearly.

I need this information in order to successfully implement one of the Sudoku
rules, the so called x-wing rule, which explanation can be found at:
http://www.sudokuoftheday.com/pages/techniques-8.php

I can find my way around with arrays, but with hashes I am not familiar at
all.

Again, thank you for your help.

Ruby Student

···

On Sat, Sep 20, 2008 at 10:47 AM, Robert Klemme <shortcutter@googlemail.com>wrote:

On 19.09.2008 20:21, Ruby Student wrote:

[Note: parts of this message were removed to make it a legal post.]

Team,
Is there a quick (perhaps one liner) way to initialize the following
hashes
into just one hash?

def xwing(ia)

p ia

puts " "
p @xwing

  r1 = {"1" => 0, "2" => 0, "3" => 0, "4" => 0, "5" => 0, "6" => 0, "7" =>
0, "8" => 0, "9" => 0}
  r2 = {"1" => 0, "2" => 0, "3" => 0, "4" => 0, "5" => 0, "6" => 0, "7" =>
0, "8" => 0, "9" => 0}
  r3 = {"1" => 0, "2" => 0, "3" => 0, "4" => 0, "5" => 0, "6" => 0, "7" =>
0, "8" => 0, "9" => 0}
  r4 = {"1" => 0, "2" => 0, "3" => 0, "4" => 0, "5" => 0, "6" => 0, "7" =>
0, "8" => 0, "9" => 0}
  r5 = {"1" => 0, "2" => 0, "3" => 0, "4" => 0, "5" => 0, "6" => 0, "7" =>
0, "8" => 0, "9" => 0}
  r6 = {"1" => 0, "2" => 0, "3" => 0, "4" => 0, "5" => 0, "6" => 0, "7" =>
0, "8" => 0, "9" => 0}
  r7 = {"1" => 0, "2" => 0, "3" => 0, "4" => 0, "5" => 0, "6" => 0, "7" =>
0, "8" => 0, "9" => 0}
  r8 = {"1" => 0, "2" => 0, "3" => 0, "4" => 0, "5" => 0, "6" => 0, "7" =>
0, "8" => 0, "9" => 0}
  r9 = {"1" => 0, "2" => 0, "3" => 0, "4" => 0, "5" => 0, "6" => 0, "7" =>
0, "8" => 0, "9" => 0}

end

(0..8).each do |r|
xwing(@xwing[[r][0]]) # @xwing is defined previously
end

Actually, I wanted just one hash, @frequency, but I did not know how to do
it.

Err, what? You know how to create nine hashes but you do not know how to
create one? I'm suspecting that there is something missing from your
posting.

Maybe you wanted something like this:

irb(main):004:0> require 'pp'
=> true
irb(main):005:0> pp Array.new(9) { Hash[*(1..9).map
{|i|[i.to_s,0]}.flatten] }
[{"6"=>0, "7"=>0, "8"=>0, "9"=>0, "1"=>0, "2"=>0, "3"=>0, "4"=>0, "5"=>0},
{"6"=>0, "7"=>0, "8"=>0, "9"=>0, "1"=>0, "2"=>0, "3"=>0, "4"=>0, "5"=>0},
{"6"=>0, "7"=>0, "8"=>0, "9"=>0, "1"=>0, "2"=>0, "3"=>0, "4"=>0, "5"=>0},
{"6"=>0, "7"=>0, "8"=>0, "9"=>0, "1"=>0, "2"=>0, "3"=>0, "4"=>0, "5"=>0},
{"6"=>0, "7"=>0, "8"=>0, "9"=>0, "1"=>0, "2"=>0, "3"=>0, "4"=>0, "5"=>0},
{"6"=>0, "7"=>0, "8"=>0, "9"=>0, "1"=>0, "2"=>0, "3"=>0, "4"=>0, "5"=>0},
{"6"=>0, "7"=>0, "8"=>0, "9"=>0, "1"=>0, "2"=>0, "3"=>0, "4"=>0, "5"=>0},
{"6"=>0, "7"=>0, "8"=>0, "9"=>0, "1"=>0, "2"=>0, "3"=>0, "4"=>0, "5"=>0},
{"6"=>0, "7"=>0, "8"=>0, "9"=>0, "1"=>0, "2"=>0, "3"=>0, "4"=>0, "5"=>0}]
=> nil
irb(main):006:0>

However, given the structure of your Hashes I wonder why you do not want to
use Arrays instead. E.g.

irb(main):001:0> pp Array.new(9) { Array.new(9, 0) }
[[0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0]]
=> nil

Or even use a Matrix.

irb(main):006:0> require 'matrix'
=> true
irb(main):007:0> pp Matrix.zero 9
Matrix[[0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0,
0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0
], [0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0,
0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0], [
0, 0, 0, 0, 0, 0, 0, 0, 0]]
=> nil
irb(main):008:0> pp Matrix.zero(9).to_a
[[0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0]]
=> nil
irb(main):009:0>

Kind regards

       robert

Robert,

First, thank you for your help and sample code.

You're welcome.

What I need to do is to pass an integer compose of minimum 2 digits and
maximum of 8 and count the how many time a digit appears.

That's easy.

irb(main):006:0> i = rand 100000000
=> 3976173
irb(main):007:0> h = Hash.new 0
=> {}
irb(main):008:0> i.to_s(10).scan(/\d/) {|dg| h[dg] += 1}
=> "3976173"
irb(main):009:0> h
=> {"6"=>1, "7"=>2, "9"=>1, "1"=>1, "3"=>2}
irb(main):010:0>

For example, I have a multidimensional array (9x9), which I then take each
row and each column at a time.

This is a _two_ dimensional Array.

For instance, the following are two rows extracted from the 9x9 array:

r1 = [345, 8, 459, 125679, 123, 45679, 379, 679, 79]
r8 = [9, 4, 6789, 356, 1, 357, 2356, 257, 67]

So, for row r1:
1s = 2, 2s = 2, 3s = 3, 4s = 3, 5s = 4, 6s = 3, 7s = 5, 8s = 1, 9s = 6

The same reasoning follows for r8.
So the 9x9 hash represents the 9x9 array for Sudoku, but instead of
representing a Sudoku element, the key = the number while the value is the
count (frequency) of that key.
I am not sure if I am explaining myself clearly.

Me, too. :wink: Given the fact that you are dealing with Sudoku it is a complete mystery to me why you want to count "digits". It seems, a Sudoku can have _numbers_ in all locations and you want to make sure that no number appears twice in a row and in a column. Basically there are many ways to do this, one would be a bit set (you can use an integer for that, see at end).

I need this information in order to successfully implement one of the Sudoku
rules, the so called x-wing rule, which explanation can be found at:
http://www.sudokuoftheday.com/pages/techniques-8.php

I can find my way around with arrays, but with hashes I am not familiar at
all.

Since you are indexing by number (or more precisely: digit) anyway what do you gain by using a Hash?

Cheers

  robert

A half baked example to illustrate what I mean with the bit set check:

#!/bin/env ruby

require 'pp'

class Sudoku
   def initialize(size)
     raise ArgumentError unless 2 <= size
     @size = size
     @dat = Array.new(size * size)
     @rows = Array.new(size, 0)
     @cols = Array.new(size, 0)
   end

   def [](x,y)
     @dat[pos(x,y)]
   end

   def []=(x,y,v)
     raise "Not allowed" if @rows[x][v] == 1 || @cols[y][v] == 1
     @dat[pos(x,y)] = v
     @rows[x] |= 1 << v
     @cols[y] |= 1 << v
   end

   def to_s
     s = ""
     @size.times do |i|
       s << "[" << @dat[i * @size, @size].join(", ") << "]\n"
     end
     s
   end

private
   def pos(x,y)
     raise ArgumentError unless [x,y].all? {|a| Integer === a}
     x * @size + y
   end
end

s = Sudoku.new 9

s[2,0] = 1
puts s

s[1,0] = 1

···

On 20.09.2008 21:30, Ruby Student wrote:

On Sat, Sep 20, 2008 at 10:47 AM, Robert Klemme > <shortcutter@googlemail.com>wrote:

On 19.09.2008 20:21, Ruby Student wrote:

Again, thanks a bunch.
You have given me enough material for a good few days to digest.
I'll play and learn from your sample code.

Thanks again,

Ruby Student

···

On Sun, Sep 21, 2008 at 4:47 AM, Robert Klemme <shortcutter@googlemail.com>wrote:

On 20.09.2008 21:30, Ruby Student wrote:

On Sat, Sep 20, 2008 at 10:47 AM, Robert Klemme >> <shortcutter@googlemail.com>wrote:

On 19.09.2008 20:21, Ruby Student wrote:

First, thank you for your help and sample code.

You're welcome.

What I need to do is to pass an integer compose of minimum 2 digits and

maximum of 8 and count the how many time a digit appears.

That's easy.

irb(main):006:0> i = rand 100000000
=> 3976173
irb(main):007:0> h = Hash.new 0
=> {}
irb(main):008:0> i.to_s(10).scan(/\d/) {|dg| h[dg] += 1}
=> "3976173"
irb(main):009:0> h
=> {"6"=>1, "7"=>2, "9"=>1, "1"=>1, "3"=>2}
irb(main):010:0>

For example, I have a multidimensional array (9x9), which I then take each

row and each column at a time.

This is a _two_ dimensional Array.

For instance, the following are two rows extracted from the 9x9 array:

r1 = [345, 8, 459, 125679, 123, 45679, 379, 679, 79]
r8 = [9, 4, 6789, 356, 1, 357, 2356, 257, 67]

So, for row r1:
1s = 2, 2s = 2, 3s = 3, 4s = 3, 5s = 4, 6s = 3, 7s = 5, 8s = 1, 9s = 6

The same reasoning follows for r8.
So the 9x9 hash represents the 9x9 array for Sudoku, but instead of
representing a Sudoku element, the key = the number while the value is the
count (frequency) of that key.
I am not sure if I am explaining myself clearly.

Me, too. :wink: Given the fact that you are dealing with Sudoku it is a
complete mystery to me why you want to count "digits". It seems, a Sudoku
can have _numbers_ in all locations and you want to make sure that no number
appears twice in a row and in a column. Basically there are many ways to do
this, one would be a bit set (you can use an integer for that, see at end).

I need this information in order to successfully implement one of the

Sudoku
rules, the so called x-wing rule, which explanation can be found at:
http://www.sudokuoftheday.com/pages/techniques-8.php

I can find my way around with arrays, but with hashes I am not familiar at
all.

Since you are indexing by number (or more precisely: digit) anyway what do
you gain by using a Hash?

Cheers

       robert

A half baked example to illustrate what I mean with the bit set check:

#!/bin/env ruby

require 'pp'

class Sudoku
def initialize(size)
   raise ArgumentError unless 2 <= size
   @size = size
   @dat = Array.new(size * size)
   @rows = Array.new(size, 0)
   @cols = Array.new(size, 0)
end

def [](x,y)
   @dat[pos(x,y)]
end

def []=(x,y,v)
   raise "Not allowed" if @rows[x][v] == 1 || @cols[y][v] == 1
   @dat[pos(x,y)] = v
   @rows[x] |= 1 << v
   @cols[y] |= 1 << v
end

def to_s
   s = ""
   @size.times do |i|
     s << "[" << @dat[i * @size, @size].join(", ") << "]\n"
   end
   s
end

private
def pos(x,y)
   raise ArgumentError unless [x,y].all? {|a| Integer === a}
   x * @size + y
end
end

s = Sudoku.new 9

s[2,0] = 1
puts s

s[1,0] = 1

Robert,