1

I have two nested arrays:

array1 = [[String_1, [String_2, [String_3.1, String_3.2, …]…]…] String_4…]
array2 = [[String_3.1, [String_3.1.1, String_3.1.2]], [String_3.2, [String_3.2.1, String_3.2.2]]]

I need to replace String_3.1 in array1 with the matching part of array2:

[String_3.1, [String_3.1.1, String_3.1.2]]

This whole part should slip into the position of String_3.1 in array1.

I can't access the values to exchange by the find_index method because they are buried in the structure. I cannot flatten the array because the structure needs to stay intact.

I tried an approach with a recursive function:

def find_insert_point(array1)
  array1.each do |value|
    if value.is_a?(Array) == true
      find_insert_point(value)
      puts "#{value}" if value.class == String
    end
  end
end

This iterates through the entries without flattening the array. But I cannot use map! to alter the underlying real array1 structure while iterating over array2 data (not included in the code).

Is there any way to search for a specific index (e.g. by string) in a nested array with multiple levels and exchange a hit with other data (e.g. a sub-array)?

2
  • 1
    String_3.1, etc. are invalid. They must be something else. 1 is an invalid method name. Commented Sep 29, 2015 at 2:52
  • 1
    I suggest you edit to make array1 and array valid arrays of strings, and show your desired output, so that readers who give answers can better show how the output is obtained. Commented Sep 29, 2015 at 2:53

2 Answers 2

1

Assuming that the substitution array is not deeply recursed, here you go:

array1 = [['String_1', 
          ['String_2', ['String_3.1', 'String_3.2']]],
           'String_4']
array2 = [['String_3.1', ['String_3.1.1', 'String_3.1.2']],
          ['String_3.2', ['String_3.2.1', 'String_3.2.2']]]

def subst arr, hsh 
  arr.map do |e| 
    Array === e ? subst(e, hsh) : hsh[e] ? [e, hsh[e]] : e
  end
end
subst array1, array2.to_h

#⇒ [
#  [0] [
#    [0] "String_1",
#    [1] [
#      [0] "String_2",
#      [1] [
#        [0] [
#          [0] "String_3.1",
#          [1] [
#            [0] "String_3.1.1",
#            [1] "String_3.1.2"
#          ]
#        ],
#        [1] [
#          [0] "String_3.2",
#          [1] [
#            [0] "String_3.2.1",
#            [1] "String_3.2.2"
#          ]
#        ]
#      ]
#    ]
#  ],
#  [1] "String_4"
# ]
Sign up to request clarification or add additional context in comments.

Comments

1

If I understand your question correctly, you could use recursion to perform the substitution(s).

Question

Suppose we have:

array1 = [["cat", ["dog", ["cow", ["pig", "yak"], "owl"], "emu"], "hog"], "elk" ]
array2 = [["pig", ["ram", "ape"]], ["cow", ["bat", "fox"]]]

I assume:

  • each element of array2 has the form [str, arr] where str is a string and arr is an array (which may contain strings and/or arrays, with any level of nesting) and
  • given a string str, you wish to replace every instance of str in array1 or in any nested array in array1 with h2[str], where:

h2 = Hash[array2]
  #=> {"pig"=>["ram", "ape"], "cow"=>["bat", "fox"]} 

Code

def replace_it(arr1, arr2, str)
  arr = Marshal.load(Marshal.dump(arr1))
  recurse(arr, str, Hash[arr2][str])
  arr
end

def recurse(arr, str, replace)
  arr.size.times do |i|
    case arr[i]
    when Array then recurse(arr[i], str, replace)
    else arr[i] = [str, replace] if arr[i] == str
    end
  end
end

The methods Marshal::dump and Marshal::dump are used to create a deep copy of array1 so that it will not be mutated. If it is desired that array1 be modified in place, the line containing those methods should be deleted and arr changed to arr1 in the last two lines.

Examples

replace_it(array1, array2, "pig")
  #=> [["cat", ["dog", ["cow", [["pig", ["ram", "ape"]], "yak"], "owl"],
  #     "emu"], "hog"], "elk"] 

replace_it(array1, array2, "cow")
  #=> [["cat", ["dog", [["cow", ["bat", "fox"]], ["pig", "yak"],
  #     "owl"], "emu"], "hog"], "elk"] 

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.