1

I have three arrays: g, a and b. g has two groups of one or more consecutive nil values. The first (second) group contains a.size (b.size) nils. I wish to replace each nil in the first (second) group with the corresponding element of a (b). For example, if:

g = [1, 2, nil, nil, nil, 3, nil, nil, nil, nil]
a = [55, 45, 56]
b = [100, 200, 300, 400]

I wish g to become:

 [1, 2, 55, 45, 56, 3, 100, 200, 300, 400]

How can I do that?

3
  • result = [1,2, elements of a, 3,elements of b] Commented Jul 5, 2015 at 8:40
  • The result of what? Why not just write g out "correctly" the first time? What are you trying to accomplish here? Commented Jul 5, 2015 at 8:43
  • I edited to clarify. Please re-open. Downvoters: please consider removing your downvote ( unless, of course, you are displeased with my edit). Commented Jul 5, 2015 at 20:04

4 Answers 4

5

The []= method can assign like this, one of its variants is

foo[insertion_point, length] = values

(there is also a version that takes a range instead of this pair of values)

g = [1,2,nil,nil,nil,3,nil,nil,nil,nil]
a = [55,45,56]
b = [100,200,300,400]

g[2, a.size] = a
g #=> [1, 2, 55, 45, 56, 3, nil, nil, nil, nil]
g[6, b.size] = b
g #=> [1, 2, 55, 45, 56, 3, 100, 200, 300, 400]

As long as the gaps are the same size as the arrays you are inserting, you wouldn't need to do anything about the nils

Sign up to request clarification or add additional context in comments.

Comments

1
g.map!{|e| e || a.shift || b.shift}
# => [1, 2, 55, 45, 56, 3, 100, 200, 300, 400]

2 Comments

I like this, but would prefer c=a+b; c.map { |e| e.nil? ? c.shift : e }. nil? in case any elements equal false.
@CarySwoveland Right. That depends on what the OP has. As always, you are the best supporter of my answer.
1

I set up an enumurator and pull items from it whenever necessary. Either of these extends easily to more input lists

itr = (a + b).to_enum
g.map!{ |e| e.nil? || itr.next }

or in this case [a, b] can be replaced with a more general tree

itr = [a, b].flatten.to_enum
g.map!{ |e| e.nil? || itr.next }

3 Comments

Interesting use of an enumerator. Similar to @sawa, but non-destructive of a and b. (Of course, sawa could operate on copies of a and b). Maybe a+b rather than [a,b].flatten. You could use to_enum instead of each.
@CarySwoveland, I would prefer if there was a version of flatten that returns an enumerator. It seems overkill to define one for this question where it's not apparent whether the overhead of copying is significant or not.
Yes, plus you are creating two temporary arrays (to be garbage-collected) in order to create the enumerator whose purpose is to avoid creating an array. :-)
-1

I think you can do it in this way:

g.insert(6, *b); // inserts b into 6 index
g.insert(2, *a); // inserts a into 2 index
g.compact! // removes the nil elements

Note that we are inserting in the reverse way so as to not disturb the indexes.

2 Comments

The inserts would have to be done in reverse (eg. 6 then 2) with this method or else the second insert index would be incorrect because the array has already had elements inserted at a prior location.
@user2864740 yeah, thanks for pointing out. Didn't cross my mind, my bad. Thanks anyway :)

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.