2010-01-11 41 views
14

Tôi có một mảng 2 chiều trong Ruby mà tôi muốn tạo một bản sao làm việc. Rõ ràng tôi không thể làm điều này;Có cách nào đơn giản để sao chép mảng đa chiều trong Ruby không?

array=[[3,4],[5,9],[10,2],[11,3]] 
temp_array=array 

vì bất kỳ sửa đổi nào tôi thực hiện cho temp_array cũng sẽ được tạo thành mảng, vì tôi vừa sao chép mã định danh đối tượng. Tôi nghĩ rằng tôi sẽ có thể để có được xung quanh này bằng cách sử dụng đơn giản;

temp_array=array.dup 

nhưng điều này không làm việc như temp_array chỉ đơn giản là một mảng của định danh đối tượng mà có được nhân đôi vì vậy tôi vẫn kết thúc điều chỉnh các mảng ban đầu (nếu tôi hiểu những gì đã xảy ra khi tôi đã làm điều này). Giải pháp tôi tìm thấy là làm như sau;

temp_array=[] 
array.each{|sub| temp_array << sub.dup} 

Điều này đạt được những gì tôi muốn nhưng có vẻ là một cách giải quyết khó khăn.

Tôi lo ngại về cách thức hoạt động này nếu tôi không biết mảng của mình sẽ chứa gì (ví dụ: nếu có thể một số phần của mảng có 3 chiều). Tôi có khả năng sẽ phải kiểm tra lớp của từng thành viên của mảng để xem liệu nó có phải được lặp lại để nhân đôi nó hay không. Không phải là một nhiệm vụ bất khả thi chút nào, nhưng nó có vẻ lộn xộn với tôi. Đây có phải chỉ đơn giản là hậu quả của Ruby thiếu sự hỗ trợ tích hợp cho các mảng đa chiều hoặc có một hàm dựng sẵn đơn giản để làm điều này mà tôi đã bỏ lỡ không?

Trả lời

29

Đây là "Ruby-esque" cách để xử lý nó:

temp_array = Marshal.load(Marshal.dump(your_array_to_be_cloned))

+3

Đó là cách. Tôi thích gắn bó mã đó trong Object.deep_copy. –

+0

Tuyệt vời, thankyou. Điều này thực sự giải thích toàn bộ điều Marshalling cho tôi (mặc dù tôi cần phải đi và làm một số đọc nhiều hơn để thực sự có được đầu của tôi xung quanh nó). – brad

-7

Hãy thử điều này:

temp_array = array.clone 
-8

Bạn có thể sử dụng theo quy định array.clonehere. Điều đó sẽ cung cấp cho bạn một bản sao của đối tượng ban đầu, và không chỉ là một con trỏ.

2

Như những người khác đã chỉ ra, bạn có thể sử dụng bản sao. Điều này sẽ không hoạt động, tuy nhiên, vì nó là một bản sao nông, do đó, mảng phụ (điều này không thực sự là một mảng đa chiều, tôi nghĩ) sẽ không nhận được nhân bản. Vì các mảng là các đối tượng có thể thay đổi được trong Ruby, các mảng con sẽ bị thay đổi. Ví dụ: hãy xem điều này ra

>> blah = [[3,5],6] 
=> [[3, 5], 6] 
>> joe = blah.clone 
=> [[3, 5], 6] 
>> joe[0] 
=> [3, 5] 
>> joe[0].push "blah" 
=> [3, 5, "blah"] 
>> blah 
=> [[3, 5, "blah"], 6] 

Vì vậy, bạn có thể thấy, chỉ làm bản sao sẽ không hoạt động. Nhưng bạn biết rằng, do đó câu hỏi của bạn.

Tôi đã nấu món này ngay bây giờ. Điều này sẽ làm cho đến khi bạn tìm ra cách Ruby thực sự để làm điều đó (tôi chỉ làm việc trong Ruby, tôi không phải là một chuyên gia).

def dup_recursive(new_array, old_array) 
    old_array.each do |item| 
    if item.class == Array 
     new_array << dup_recursive([], item) 
    else 
     new_item = item.dup rescue new_item = item # in case it's got no dupe, like FixedNum 
     new_array << new_item 
    end 
    new_array 
    end 
end 

array=[[3,[9,12]],[5,9],[10,2],[11,3]] 
new_array = Array.new 
dup_recursive(new_array, array) 
puts array.inspect 
puts new_array.inspect 

Tôi biết, tôi không sử dụng cách gõ vịt, nhưng tôi rất vui khi được học về cách thực hiện điều này mà không yêu cầu lớp của đối tượng được đề cập.

Chỉnh sửa: Tôi chỉ nên tìm kiếm các bản sao thâm nhập trong Google, nhưng đôi khi tôi thích viết mã:) ... anyway, giải pháp khác được trình bày - Marshal.load(Marshal.dump(array)) - cũng sẽ hoạt động cho Hashes và vv, vì vậy nó tốt hơn.

+0

Đó thực sự là một đoạn mã nhỏ đẹp. Đó là những gì tôi sợ tôi sẽ phải viết để giải quyết vấn đề này nhưng thực hiện tốt hơn nhiều so với tôi sẽ có. Điều thú vị là số người đã đi thẳng vào giải pháp nhân bản - vấn đề này rõ ràng là không được hiểu rõ bởi nhiều người theo chủ nghĩa Ruby. – brad

+0

Có lẽ đúng, Brad, nhưng mặt khác, có thể bạn có một mẫu xấu (của mọi người, câu trả lời). Có thể là thời gian trong ngày, từ ngữ của câu hỏi, hoặc bất cứ điều gì khác. Hoặc có thể là vấn đề này không được hiểu bởi nhiều người Ruby. Thật không may Rails loại lá chắn bạn từ phải hiểu bất cứ điều gì nhiều ở tất cả :) –

-1

Thử chạy array.dup trên mỗi mảng phụ trong mảng.

c = [] 
    array.each do |row| 
     c << row.dup 
    end 
0

Bạn có thể sử dụng DeepEnumerable 's deep_dup cho việc này:

>> require 'deep_enumerable' 

>> array=[[3,4],[5,9],[10,2],[11,3]] 

>> temp_array=array.deep_dup 
>> array.each{|sub| sub << "XXX"} 

>> array 
=> [[3, 4, "XXX"], [5, 9, "XXX"], [10, 2, "XXX"], [11, 3, "XXX"]] 

>> temp_array 
=> [[3, 4], [5, 9], [10, 2], [11, 3]] 
2

Có cách tốt nhất để làm chính xácbản sao thực của mảng đa chiều trong Ruby là Marshalling.

Đây là của Ruby cú pháp của marshalling:

Marshal.load(Marshal.dump(Name_Of_Your_Original_Array))

Chúng ta hãy xem làm thế nào để sử dụng cú pháp này sử dụng trên dụ ví dụ:

array=[[3,4],[5,9],[10,2],[11,3]] temp_array=array

Trong ví dụ này, nó chỉ tạo một đối tượng trỏ cùng một vị trí bộ nhớ của mảng, nó không làm bản sao thực của mảng của chúng ta. Ở đây, Nếu bạn sửa đổi giá trị của temp_array thì nó sẽ tự động phản ánh các thay đổi trong mảng ban đầu là biến số array trong ví dụ của chúng tôi. Vì vậy, làm thế nào để chúng tôi ngăn chặn các thay đổi tự động xảy ra trong mảng ban đầu của chúng tôi, chúng tôi có thể làm điều này bằng cách marshalling.

Vì vậy! làm cách nào để chúng tôi thực hiện việc này, trong ví dụ này, chúng tôi cần tạo một bản sao thực sự của các mẫu vào temp_array.

Hãy xem, làm thế nào để làm điều này:

array=[[3,4],[5,9],[10,2],[11,3]] temp_array = Marshal.load(Marshal.dump(array))

Bây giờ, chúng tôi đã thực hiện các bản sao thực sự của mảng đa chiều của chúng tôi, nếu bạn sửa đổi bất kỳ giá trị của temp_array của bạn sau đó những thay đổi sẽ không phản ánh array gốc của bạn.

Các vấn đề liên quan