web-dev-qa-db-ja.com

Ruby多次元配列

ここで問題を見つけるのは私の能力の不足だけかもしれませんが、Rubyで多次元配列を作成する方法については何も見つかりません。

誰かがそれを行う方法の例を教えてもらえますか?

43
andkjaer

ブロックをArray.newに渡すことができます

Array.new(n) {Array.new(n,default_value)}

ブロックを返す値は、最初の配列の各インデックスの値になります。

そう..

Array.new(2) {Array.new(2,5)} #=> [[5,5],[5,5]]

array[x][y]を使用してこの配列にアクセスできます

2番目の配列のインスタンス化でも、ブロックをデフォルト値として渡すことができます。そう

Array.new(2) { Array.new(3) { |index| index ** 2} } #=> [[0, 1, 4], [0, 1, 4]]
22
Orlando

単なる説明:

arr = Array.new(2) {Array.new(2,5)} #=> [[5,5],[5,5]]

以下とまったく同じではありません:

arr = Array.new(2, Array.new(2, 5))

後者の場合、試してください:

arr[0][0] = 99

これはあなたが得たものです:

[[99,5], [99,5]]
7
Xavier Nayrac

マルチ配列(サイズ2)を初期化するには2つの方法があります。他のすべての回答は、デフォルト値の例を示しています。

各サブ配列を宣言します(ランタイムで実行できます):

multi = []
multi[0] = []
multi[1] = []

または、初期化時に親配列のサイズを宣言します。

multi = Array.new(2) { Array.new }

使用例:

multi[0][0] = 'a'
multi[0][1] = 'b'
multi[1][0] = 'c'
multi[1][1] = 'd'

p multi # [["a", "b"], ["c", "d"]]
p multi[1][0] # "c"

したがって、最初の方法をラップして、次のように使用できます。

@multi = []
def multi(x, y, value)
  @multi[x] ||= []
  @multi[x][y] = value
end

multi(0, 0, 'a')
multi(0, 1, 'b')
multi(1, 0, 'c')
multi(1, 1, 'd')

p @multi # [["a", "b"], ["c", "d"]]
p @multi[1][0] # "c"
5
Evmorov

上記の方法は機能しません。

n = 10
arr = Array.new(n, Array.new(n, Array.new(n,0.0))) 
arr[0][1][2] += 1
puts arr[0][2][2]

に等しい

n = 10
a = Array.new(n,0.0)
b = Array.new(n,a)
arr = Array.new(n, b) 
arr[0][1][2] += 1
puts arr[0][2][2]

配列aを変更し、配列aの要素を出力するため、0.0ではなく1.0を出力します。

3
kipar

PHPスタイルの多次元配列をRubyで最近再現しなければなりませんでした。

# Produce PHP-style multidimensional array.
#
# Example
#
# arr = Marray.new
#
# arr[1][2][3] = "foo"
# => "foo"
#
# arr[1][2][3]
# => "foo"

class Marray < Array
  def [](i)
    super.nil? ? self[i] = Marray.new : super
  end
end
1
Damian Borowski

実際、これは上記のブロックメソッドよりもはるかに高速です。

arr = Array.new(n, Array.new(n, Array.new(n,0.0))) 

arr[0][1][2] += 1
1
Kri-ban

使用にはXKeys Gemも使用できます。

require 'xkeys'

regular = [].extend XKeys::Auto
regular[1,2,3] = 4
# [nil, [nil, nil, [nil, nil, nil, 4]]]
regular[3,2,1, :else=>0] # 0
# Note: regular[1,2] is a slice
# Use regular[1,2,{}] to access regular[1][2]

sparse = {}.extend XKeys::Hash
sparse[1,2,3] = 4
# {1=>{2=>{3=>4}}}
path=[1,2,3]
sparse[*path,{}] # 4
0
Brian K

Rubyでの3D配列クラスの実装を次に示します。この場合、デフォルト値は0です

class Array3
 def initialize
   @store = [[[]]]
 end

 def [](a,b,c)
  if @store[a]==nil ||
    @store[a][b]==nil ||
    @store[a][b][c]==nil
   return 0
  else
   return @store[a][b][c]
  end
 end

 def []=(a,b,c,x)
  @store[a] = [[]] if @store[a]==nil
  @store[a][b] = [] if @store[a][b]==nil
  @store[a][b][c] = x
 end
end


array = Array3.new
array[1,2,3] = 4
puts array[1,2,3] # => 4
puts array[1,1,1] # => 0
0
edymerchk

配列はRubyのオブジェクトであり、オブジェクトは(デフォルトでは)名前を付けたりオブジェクト参照に名前を付けたりするだけでは作成されないことを覚えておくと役立ちます。以下は、3次元配列を作成し、確認のために画面にダンプするためのルーチンです。

 def Create3DimensionArray(x、y、z、default)
 n = 0#検証コードのみ
 ar = Array.new(x)
 for i in 0 ... x 
 ar [i] = Array.new(y)
 in j in 0 ... y 
 ar [i] [j] = Array.new( z、デフォルト)
 for k in 0 ... z#検証コードのみ
 ar [i] [j] [k] = n#検証コードのみ
 n + = 1#検証コードのみ
 end#検証コードのみ
 end 
 end 
 return ar 
 end 
 
 #サンプルを作成し、検証する
 ar = Create3DimensionArray(3、7、10、0)
 
 for x in ar 
 puts "||" 
 [y] for x 
 puts "|" 
 z for y 
 printf "%d"、z 
 end 
 end 
終わり
0
mhdecoursey

おそらく、ハッシュを使用して多次元配列をシミュレートできます。ハッシュキーは、任意のRubyオブジェクトによって可能です。したがって、配列を取ることもできます。

例:

marray = {}
p marray[[1,2]]   #-> nil
marray[[1,2]] = :a
p marray[[1,2]]   #-> :a

この考えに基づいて、新しいクラスを定義できます。

簡単なシナリオ:

=begin rdoc
Define a multidimensional array.

The keys must be Fixnum.

The following features from Array are not supported:
* negative keys (Like Array[-1])
* No methods <<, each, ...
=end
class MArray
  INFINITY = Float::INFINITY
=begin rdoc
=end
  def initialize(dimensions=2, *limits)
    @dimensions = dimensions
    raise ArgumentError if limits.size > dimensions
    @limits = []
    0.upto(@dimensions-1){|i|
      @limits << (limits[i] || INFINITY)
    }
    @content = {}
  end
  attr_reader :dimensions
  attr_reader :limits
=begin rdoc
=end
  def checkkeys(keys)
    raise ArgumentError, "Additional key values for %i-dimensional Array" % @dimensions if keys.size > @dimensions
    raise ArgumentError, "Missing key values for %i-dimensional Array" % @dimensions if keys.size != @dimensions
    raise ArgumentError, "No keys given" if keys.size == 0
    keys.each_with_index{|key,i|
      raise ArgumentError, "Exceeded limit for %i dimension" % (i+1) if key > @limits[i]
      raise ArgumentError, "Only positive numbers allowed" if key < 1

    }
  end
  def[]=(*keys)
    data = keys.pop
    checkkeys(keys)
    @content[keys] = data
  end
  def[](*keys)
    checkkeys(keys)
    @content[keys]
  end
end

これは次のように使用できます。

arr = MArray.new()
arr[1,1] = 3
arr[2,2] = 3

定義済みのマトリックス2x2が必要な場合は、次のように使用できます。

arr = MArray.new(2,2,2)
arr[1,1] = 3
arr[2,2] = 3
#~ arr[3,2] = 3  #Exceeded limit for 1 dimension (ArgumentError)

多次元配列ではなく、2次元配列で<<eachなどのコマンドを処理する方法を想像できました。

0
knut