2015-11-05 3 views
3

Учитывая этот вход:уплощение вложенные массивы в Powershell

$values = @(1, @(2, 3), $null, @(@(4), 5), 6) 

Что необходимо для создания чистой итерации/трубопровода через

1,2,3,4,5,6 

?

Условия:

  • Она не должна включать в себя $null на выходе.
  • Это должно привести к пустым массивам, даже если ввод равен $ null или все значения ввода равны $ null.

Бонус:

  • Он должен показать [1,2,3,4,5,6] в результате ConvertTo-Json -Compress
  • Он предпочтительно должен быть чистым и запоминающимся, то есть не византийский манипуляция трубы предпочтительно не зависимости от пользовательских функций, если вообще возможно.

Я видел Flatten array in PowerShell, решения там, похоже, не соответствуют условиям.

+0

Вам нужно сгладить только массивы? Как насчет других типов коллекций? – PetSerAl

+0

Решение, которое поддерживает все типы коллекций, приветствуется. Цель состоит в том, чтобы иметь возможность выполнять итерацию, вызывать 'Select-Object' и т. Д. Все это, не нарушая« $ null »или не влияя на глубину вложенности. – Tomalak

+0

Я очень соблазн построить рекурсивную функцию, но это нарушит бонус – Matt

ответ

3

Ради полноты, как это может помочь другому пользователю, я хотел включить очень простую рекурсивная функция, которая охватывает большинство ваших критериев, кроме ...

Она предпочтительно должна быть чистой и запоминающейся, то есть не византийская манипуляция трубы preferre d, не зависит от пользовательских функций, если это вообще возможно.

Я знаю, что [вы] могли бы сделать, что [ваш] самостоятельно но, возможно, он может помочь кому-то еще. Я видел это, когда говорил о PowerShell, называемый разворачиванием массивов. Если вы продолжите поиск, это слово может принести больше плода.

Используя $input, как это было предназначено, мы выполняем довольно простую функцию. Если один из переданных элементов является элементом массива, мы снова вызываем функцию до тех пор, пока мы не сведем к необработанным значениям.

function Flatten-Array{ 
    $input | ForEach-Object{ 
     if ($_ -is [array]){$_ | Flatten-Array}else{$_} 
    } | Where-Object{![string]::IsNullorEmpty($_)} 
    # | Where-Object{$_} would also work. 
} 

Так пример вызова будет

@(1, @(2, 3), $null, @(@(4), 5), 6) | Flatten-Array | ConvertTo-Json -Compress 

Какие сетки [1,2,3,4,5,6]. $null s покрыты одной из нескольких простых статей Where.

+0

Ваш 'Flatten-Array' не отбрасывает' $ null'. Попробуйте следующее: '@ (1, @ (2, 3), $ null, @ (@ (4), 5), 6) | Сплав-массив | % GetType'. Это 'ConvertTo-Json', который сбрасывает' $ null'. – PetSerAl

+0

@PetSerAl Спасибо. Простой, где это покрывает. Я старался держать его в тени. – Matt

+0

@Xalorous '$ input' - это [автоматическая переменная] (https://technet.microsoft.com/en-us/library/hh847768.aspx). Его не нужно определять. Не уверен, почему он не работает для вас. – Matt

1

Примечание: Не используйте $input в качестве имени переменной, это автоматический счетчик переходов, и он не будет вести себя так, как вы ожидаете. (Т. Е с ForEach-Object)

Два раунда конвейерных сплющит эту структуру для вас, ConvertTo-Json -Compress автоматически оставить из $null значения:

PS C:\> $NestedArray = @(1, @(2, 3), $null, @(@(4), 5), 6) 
PS C:\> $FlatArray = $NestedArray | ForEach-Object { $_ } | ForEach-Object { $_ } 
PS C:\> $FlatArray | ConvertTo-Json -Compress 
[1,2,3,4,5,6] 
+0

'$ input' был просто фиктивным именем, я изменил это, спасибо за подсказку. Как насчет уровней N? Разве нет способа сделать это без предварительного знания глубины гнездования? Кроме того, я хочу '$ null' out * перед *' ConvertTo-Json', отметив, что это только для того, чтобы сделать очевидным, какую результирующую структуру данных я начал с самого начала. – Tomalak

+0

Поскольку это не рекурсивно, оно не будет обрабатывать более трех уровней. – Xalorous

3

Вы можете сделать это с помощью рекурсивной команды:

$values = (1, (2, 3), $null, (,4, 5), 6) 

$values|&{ 
    process{ 
     if($null -ne [System.Management.Automation.LanguagePrimitives]::GetEnumerator($_)){ 
      $_|&$MyInvocation.MyCommand.ScriptBlock 
     }elseif($null -ne $_){ 
      $_ 
     } 
    } 
} 

Но вы должны быть уверены, что вы не проходит что-то вроде этого в качестве входных данных:

$values[0]=$values=,0 
+0

Я так много узнаю от вас! – Matt

+0

Это не * вполне * выполняет «не-византийскую» часть, но это очень интересно и поучительно. Благодаря! – Tomalak

1

Вот рекурсивный Flatten-Array функция, которая делает не используется Конвейерная обработка:

$values = @(1, @(2, 3), $null, @(@(4), 5), 6) 

function Flatten-Array{ 
    param (
     [array] $inputArray 
    ) 

    foreach ($item in $inputArray){ 
     # skip $nulls 
     if ($item -ne $null) { 
      # recurse for arrays 
      if ($item.gettype().BaseType -eq [System.Array]) { 
       Flatten-Array $item 
      } 
      else { 
      # output non-arrays 
       $item 
      } 
     } 
    } 
} 

Flatten-Array $values | %{$_.gettype()} 
+0

Mh, в чем преимущество использования конвейерной обработки? – Tomalak

+0

Вы просили, чтобы он не включал византийскую конвейерную обработку. Это самое простое и легкое для запоминания решение, которое я мог бы разработать. Через пару часов полировка может быть преобразована в расширенную функцию и будет считаться кодом «многократного использования». Если бы это было что-то, что мне нужно было делать часто, я бы подумал о добавлении его в свой профиль или пользовательский модуль. YMMV, но в сценариях я склоняюсь к функциям, возвращающим объекты, в то время как в CLI я буду использовать псевдонимы и конвейерную обработку. – Xalorous

+0

Я не хотел сказать, что я нахожу конвейерную обработку byzanzine. Я хотел сказать, что я бы не предпочел византийскую конвейерную обработку, это разница. См. Ответ PetSerAl, как и на первый взгляд, на примере византийской конвейерной обработки. – Tomalak

4

@(1, @(2, 3), $null, @(@(4), 5), 6) | %{$_} | ?{$_ -ne $null}

Выход:

1 
2 
3 
4 
5 
6 

ForEach-Object Командлет (%) сглаживает массивов по умолчанию.