J'ai deux listes stockées dans des variables: $list1 et $list2, par exemple:

$list1:

a
b
c
d

$list2:

1
2
3
4

Comment puis-je les fusionner ligne par ligne pour obtenir:

a1
b2
c3
d4

J'ai essayé d'utiliser array (@) mais il les combine simplement les uns après les autres, pas ligne par ligne, exemple:

$list1 = @(command)
$list1 += @($list2)
3
Rakha 28 avril 2017 à 16:23

3 réponses

Meilleure réponse

Pour compléter les réponses utiles basées sur for et Réponse utile de Martin Brandl basée sur le pipeline:

En combinant foreach avec .., l'opérateur de plage permet une solution concise qui fonctionne également bien:

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

Même si un tableau entier d'indices est construit en premier - 0..($list1.count-1) - cela surpasse légèrement la solution for avec de grandes listes d'entrée, et foreach et for seront nettement plus rapides que la solution basée sur le pipeline - voir ci-dessous.

Notez également comment l'interpolation de chaîne (références de variables et sous-expressions dans une seule chaîne "...") est utilisée pour garantir que le résultat est toujours une chaîne .

En revanche, si vous utilisez +, c'est le type du LHS qui détermine le type de sortie, ce qui peut entraîner des erreurs ou une sortie indésirable; Par exemple, 1 + 'a' provoque une erreur, car 1 est un entier et 'a' ne peut pas être converti en entier.


Lecture facultative: considérations relatives aux performances

  • En règle générale, les solutions foreach et for sont nettement plus rapides que les solutions basées sur des pipelines (ForEach-Object applets de commande).

  • Les pipelines sont élégants et concis, mais ils sont relativement lents.

    • Cela ne devrait pas vous empêcher de les utiliser, mais il est important de savoir qu’ils peuvent être un goulot d’étranglement des performances.

    • Les pipelines sont économes en mémoire , et pour le traitement de grandes collections qui ne rentrent pas dans la mémoire dans son ensemble, ils sont toujours le bon outil à utiliser.

  • PSv4 a introduit l '.ForEach() opérateur de collecte (méthode) peu connu, dont les performances se situent entre celles de for / foreach et de ForEach-Object < em> cmdlet .

Ce qui suit compare les performances relatives avec de grandes listes (100 000 éléments); les nombres absolus de synchronisation varieront en fonction de nombreux facteurs, mais ils devraient vous donner une idée générale:

# 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 }

Dans une machine virtuelle Windows 10 à 2 cœurs exécutant PSv5.1, j'obtiens les résultats suivants après avoir exécuté les tests plusieurs fois:

0.5  # foreach
0.7  # for
1.8  # ForEach-Object (pipeline)
1.2  # .ForEach() operator
1
mklement0 4 juil. 2018 à 02:58

Vous pouvez le faire avec une boucle For qui utilise des itérations dans l'index de chaque objet jusqu'à ce qu'il atteigne le total (.count) du premier objet:

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

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

Production:

a1
b2
c3
d4

Si vous voulez que les résultats soient dirigés vers une variable, vous pouvez mettre (par exemple) $list = avant le For.

2
Mark Wragg 28 avril 2017 à 13:30

Si vous préférez le pipelining, vous pouvez également le faire en une seule ligne:

0 .. ($list1.count -1) | ForEach-Object { $list1[$_]+$list2[$_] }
3
Martin Brandl 28 avril 2017 à 13:38