Concatenate / concatenate two lists line by line?

I have two lists stored in variables: $list1

and $list2

, for example:

$list1

:

a
b
c
d

$list2

:

1
2
3
4

How to combine them together in turn so that I end up with:

a1
b2
c3
d4

I tried using array (@), but it just concatenates them one by one and not line by line, e.g .:

$list1 = @(command)
$list1 += @($list2)

      

+3


source to share


3 answers


To supplement useful answer for

Mark Wragg
and Martin Brundle, a useful answer on the basis of the conveyor

Combining foreach

with ..

, the range operator allows for a concise solution that also works well:

foreach ($i in 0..$($list1.count-1)) { "$($list1[$i])$($list2[$i])" }

      

Despite the fact that you first create a whole array indices - 0..$($list1.count-1)

- is slightly larger than the solution for

with high input lists, and how foreach

, and for

will be much faster than a decision based on the assembly line - see below..

Also notice how string interpolation (variable references and subexpressions within the same string "..."

) are used to ensure that the result is always a string.

In contrast, if you use +

, the LHS type determines the type of output, which can lead to errors or unwanted results; for example, 1 + 'a'

raises an error because it 1

is an integer and 'a'

cannot be converted to an integer.




Additional Reading: Performance Considerations

  • Generally solutions are foreach

    and are for

    noticeably faster than pipeline based solutions ( ForEach-Object

    cmdlet based).

  • Piping is elegant and concise, but relatively slow.

    • This shouldn't stop you from using them, but it's important to know that they can be a performance bottleneck.

    • Piping is memory efficient and for handling large collections that don't fit into memory in general, they are always the right tool to use.

  • PSv4 introduces a little-known collection operator (method) .ForEach()

    whose performance ranges from for

    / foreach

    and cmdlet ForEach-Object

    .

Next, the relative performance is compared with large lists (100,000 items); absolute time numbers will vary based on many factors, but they should give you a general idea:

# Define two large lists.
$list1 = 1..100000
$list2 = 1..100000

# Define the commands as script blocks:
$cmds = { foreach ($i in 0..$($list1.count-1))  { "$($list1[$i])$($list2[$i])" } },
        { for ($i=0; $i -lt $list1.count; $i++) { "$($list1[$i])$($list2[$i])" } },
        { 0..($list1.count -1) | ForEach-Object { "$($list1[$_])$($list2[$_])" } },
        {        (0..$($list1.count-1)).ForEach({ "$($list1[$_])$($list2[$_])" }) }


# Time each command.
$cmds | ForEach-Object { '{0:0.0}' -f (Measure-Command $_).TotalSeconds }

      

On a dual core Windows 10 VM running PSv5.1, I get the following results after several tests:

0.5  # foreach
0.7  # for
1.8  # ForEach-Object (pipeline)
1.2  # .ForEach() operator

      

+1


source


If you prefer pipelining, you can also do it in one line:



0 .. ($list1.count -1) | ForEach-Object { $list1[$_]+$list2[$_] }

      

+3


source


You can do this with a loop For

that iterates over the index of each object until it reaches the common ( .count

) first object:

$list1 = 'a','b','c','d'
$list2 = 1,2,3,4

For ($i=0; $i -lt $list1.count; $i++) {
    $list1[$i]+$list2[$i]
}

      

Output:

a1
b2
c3
d4

      

If you wanted the results to go to a variable, you could put (for example) $list =

before For

.

+2


source







All Articles