Hello to all,

Having to arrays of the same size like below.

A = ["SL","MW","OP"]
B = ["RU","YF","L2"]

How can I concatenate in columns to print in parallel like below?

SL - RU
MW - YF
OP - L2

I've tried with code below but is printing all in one column

puts A << "-" << B

Thanks in advance for any help.

Recommended Answers

All 18 Replies

To iterate two arrays in parallel, you can use:

array1.zip(array2) do |element1, element2|
  # ...
end

Hello again sepp2k,

It works!

Only to know in general, how would be if I have 3 or more arrays and I wanted to print in parallel?

Thanks again for the help.

zip accepts more than one argument.

And for cases where zip does not work, you can always iterate using indices (depending on the situation, using each_index, a range or even a while loop with a manually incremented index).

Thanks so much sepp2k. I'll check zip documentation to make some tests.

Best regards

A little late to the game but hopefully this helps the situation for 3 or more lists:

require 'matrix'

m = Matrix[ [1,2,3], [2,3,4], [3,4,5], [4,5,6] ]

# transpose will get the order you want
m.transpose.to_a.each do |xs|
   puts xs.join "-"
end

# => 1-2-3-4
# => 2-3-4-5
# => 3-4-5-6

Hello L7sqr,

Thanks for your contribution. Always is good to know more ways to do something.

I've been trying your code and it works just fine. Doing manually I see that in order to work with this matrix method, is needed that all arrays have the same size. I was wondering how to print in parallel arrays that have different size.

I can think that first should be known the arrays with more number of elements and then fill with blanks the other arrays to make them of the same size.

Something like convert this:

m = Matrix[ [1,2,3], [2,3,4], [3,4,5], [4,5,6] ]

to this:

m = Matrix[ [1,2,3,""], [2,3,4,0], [3,4,5,""], [4,5,6,""] ]

How can I do this?
How many arrays does accept Matrix[...]?

Thanks in advance for your help.

Regads

Printing, in parallel, arrays of differing size make little sense.

You can either trim all arrays to be some minimal length or extend each to include a known filler value. I'd heavily suggest the former.

In either case you could simply wrap that Matrix creation code in another method that does the trimming or extending and then creates the Matrix with the modified values.

Hello L7Sqr,

Thanks again for the help and time.

Which method could wrap the matrix creation?

Regards

You can wrap the matrix code similar to:

def wrappedMatrix( *rows )
   Matrix[ *rows ]
end

That is the most simple example that accomplishes nothing. What you want is to maniupluate the *rows prior to handing them off to Matrix#[]

That would look something like the following if you wanted to trim to the shortest array (modify to suit you actual needs):

def trimmedMatrix( *rows )
   minWid = rows.collect { |r| r.size }.min
   Matrix[ *(rows.collect { |r| r[0...minWid] }) ]
end

When run, that gives you what you would expect:

trimmedMatrix( [1,2,3], [2,3,4,5,6], [3,4,5] )
# => Matrix[[1,2,3], [2,3,4], [3,4,5]]

Hello L7Sqr,

Thanks for the example. This works for the trimming part, but how to add the trimmed elements and empty elements for smaller arrays?

I mean, having this original matrix:

  m = [[1,2,3], [2,3,4,5,6], [3,4,5] ]

The first step as you suggest is trim to the smaller array size to get this trimmed matrix:

  trimmed_m = [[1,2,3], [2,3,4], [3,4,5]]

But the final matrix I want to get is:

 final_m = [[1,2,3,"",""], [2,3,4,5,6], [3,4,5,"",""]]

Having this final matrix with all arrays with the same size, I'd be able to use the transpose method you shared to print in parallel.

Thanks again for the help

Yes, I understand what you wanted exactly. I was hoping that you would take what I provided and configure it to do what you needed. Basically, you would need to find the max instead of the min and, for any array that had less than that many elements you would need to add the difference (Array#+) instead of slicing the first few elements (Array#[]).

Try some things out and post back with any problems.

Hello L7sqr,

I've tried to modify your code, but I don't understand how operates the code you have shared nor collect and the *.

I have this so far, I think that "maxWid = rows..{...}max" to get the max could be ok, but I don't get how to add the difference how you say (array#+).

#!/usr/bin/env ruby
require 'matrix'


 def trimmedMatrix( *rows )
 maxWid = rows.collect { |r| r.size }.max
 Matrix[ *(rows.collect { |r| r[0...maxWid] }) ]
 end

 p trimmedMatrix( [1,2,3], [2,3,4,5,6], [3,4,5] )

Thanks for help so far.

Array slicing is accomplished with Array#[] (the [] method on Array). If you'd like to add to an array you use Array#+ (the + method on Array).

The collect method iterates over an array of items, performs some operation, and collects the results of the operations which are returned as a new array. For example:

[1,2,3,4].collect { |i|
   i**2
}
# => [1, 4, 9, 16]

Hello L7Sqr,

I'm trying with code below, but I get error "Can't convert string into array (TypeError)"

#!/usr/bin/env ruby
require 'matrix'


 def ExtendedMatrix( *rows )
 maxWid = rows.collect { |r| r.size }.max
 Matrix[ *(rows.collect { |r| while r.size < maxWid do r + "" end  }) ]
 end

p ExtendedMatrix( [1,2,3], [2,3,4,5,6], [3,4,5] )

How to fix this?

Thanks in advance

Two issues with that:

  • Array#+ expects to add two arrays and return an array. You are not following those requirements.
  • Fixing that will result in you returning an array of nil values. The result of the while is nil within the closure and collect will only capture the result of the last operation of the closure.

To fix what you have you can do the following:

def trimmedMatrix( *rows )
   maxWid = rows.collect { |r| r.size }.max
   Matrix[ *(rows.collect { |r| r + [""]*(maxWid - r.size) }) ]
end

That is somewhat compacted so let me expand a bit:

rows.collect:
Returns an array consisting of the result of the closure for each element of rows

maxWid - r.size:
Computes the number of elements needed to fill the current array to a fixed size

[""]*:
Multiplying an array of a single value results in an array of that size filled with the original value. So [0]*10 gives you an array of 10 zeros.

r + [""]*(maxWid - r.size):
Add to r an array of "" values long enough to make r.size equal to maxWid.

Now, having done all that, I still claim that you are going about this the wrong way. If you explain what you are trying to do there is certainly a more intuitive way to go approach this problem.

Consider the case that you have to come back to this code in two months and edit it to do something slightly different - are you gonna be able to do that? Reworking the code to be more consistent will help you better understand the logic when you need to maintain things further down the line.

Hello L7Sqr,

Thanks for the nice explanation. I understand much better your code. Normally the compacted syntax trends to confuse me, but with your explanation I understood :).

What I'm trying to do is parse an XML file with REXML module and the issue is that some nodes happens one time and others child elements happens several times.

The values of each element is captured in an array and when I have completely filled the array, I want to print in that way. I mean, each array inside the array contains all values for each child element (one value or more if it is repeated).

Then, I need to finally transpose the arrays to print them as I asked at the beginnig of the post, but in order to use "transpose" method, I need to have all arrays of the same size. Because of that, the way I think is filling the smaller arrays with blanks.

Certainly there are stright ways to accomplish the parsing I'm trying, but due to my lack of knowdledge in ruby I go completing parts of my algorithm step by step. If I had more knowledge maybe seeing globally the problem, I'd do it in a another way :).

Many thanks for your help ant time again

XML is something I wish I never had to work with. Unfortunately, I am not so lucky.

Hopefully this works for you in the short term. Although, if you can manage it I'd still suggest some constraints at the higher layers (XML) if you can manage it. Something like: 'must have equal number of children' or similar. When you try to handle it at the lower layer (parsing code) you end up having to change every time the format of the XML changes.

Perhaps this is a consequence of your environment.

Hello L7Sqr,

The XML has elements with chil elements that happens only once, like Date, File name, Store Name, etc. But other child elements always could have one or more elements since are related with activities or codes that could happen once or more times. Is the way it is the XML file due to the content that stores.

Do you know if REXML is a good option to work with? or do you know another pacakge to parse XML that could be easier or faster or with better features?.

Thanks for the help.

Regards

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.