Назначение переменной внутри инструкции switch

#powershell

#powershell

Вопрос:

Всем доброго утра!

Я возился с оператором switch с тех пор, как узнал об этом в другом сообщении, которое я сделал.

У меня есть эта проблема с приведенным ниже кодом, где он печатает несколько строк с одной и той же информацией, и я понимаю, почему это так, но я не знаю, как это исправить. Я считаю, что это неправильно, когда я присваиваю переменную, но я не слишком уверен. Может ли кто-нибудь указать мне правильное направление в том, что может быть причиной проблемы? Любая помощь приветствуется.

 $gc = Get-ChildItem -Path 'C:usersabrahOneDriveDesktop'  
Foreach ($File in $gc) {
 
    switch -Wildcard ($file) {

        "deskt*" { $Desk = "This is the location: $($File.FullName)" }
        "*v*" { $VA = "This is the location: $($File.FullName)" }

    }

    $VCount = $va | Measure-Object | Select-Object -ExpandProperty Count
    $Dcount = $Desk | Measure-Object | Select-Object -ExpandProperty Count

    $PS = [pscustomobject]@{
        DesktopLocation = $Desk
        DCount          = $Dcount
        VLocation       = $VA
        VCount          = $VCount
 
    }

    $PS
}
 

О скрипте: я просто ищу, чтобы найти любые файлы на моем рабочем столе, которые начинаются с deskt , и любые с буквой V в нем. Затем я помещаю ее в пользовательский объект, пытаясь подсчитать, сколько файлов содержат эти ключевые буквы.

Вот результаты, кстати:

введите описание изображения здесь

Комментарии:

1. Я также подумал: «Может быть, я могу просто посчитать элементы в customobject, но тогда как я буду добавлять к нему?»

2. Вы продолжаете пытаться «пересчитать» все каждый раз, когда работаете с одним файлом прямо сейчас. Делайте что-то одно за раз, и это будет намного проще

Ответ №1:

Что касается подхода, основанного на вашем switch заявлении:

  • switch сам по себе способен обрабатывать коллекции, поэтому нет необходимости заключать его в foreach цикл.
  • То, что вы ищете, — это создать две коллекции из входных данных, что требует от вас:
    • инициализировать $Desk и $VA как тип данных коллекции.
    • добавьте к этим коллекциям в обработчиках switch ветвей.
 # Initialize the collections.
$Desk = [System.Collections.Generic.List[string]] @()
$VA = [System.Collections.Generic.List[string]] @()

# Make `switch` loop over the .FullName values of all items in the target dir.
switch -Wildcard ((Get-ChildItem C:usersabrahOneDriveDesktop).FullName) {
  '*deskt*' { $Desk.Add("This is the location: $_") } # add to collection
  '**v*'    { $VA.Add("This is the location: $_") }   # add to collection
}

# Construct and output the summary object
[pscustomobject] @{
  DesktopLocation = $Desk
  DCount          = $Desk.Count
  VLocation       = $VA
  VCount          = $VA.Count
}
 

Примечание:

  • Хотя в качестве типа коллекции можно использовать массив, «добавление» к массивам с = помощью, хотя и удобно, неэффективно, поскольку каждый раз новый массив должен создаваться за кулисами, учитывая, что массивы неизменяемы в отношении количества их элементов.
    Хотя это может не иметь значения для массивов, содержащих всего несколько элементов, это хорошая привычка для формирования, чтобы использовать System.Collections.Generic.List`1 ее в качестве эффективно расширяемого типа коллекции.
  • Тем не менее, учитывая, что такие операторы, как switch и foreach циклы, могут действовать как выражения при назначении переменной, если весь вывод должен быть записан в одну коллекцию, вам даже не нужен тип коллекции явно, который является кратким и эффективным; например:
    $collection = foreach ($i in 0..2) { $i 1 } сохраняет массив 1, 2, 3 в $collection ; обратите внимание, что если выводится только один объект, $collection он не будет массивом, поэтому для обеспечения того, чтобы вы могли использовать [array] $collection = ...

В качестве альтернативы, более простым решением является использование того факта, что фильтрация на основе подстановочных знаков с помощью -Filter параметра выполняется быстро, так что даже Get-ChildItem повторный вызов, скорее всего, не будет проблемой:

 $dir = 'C:usersabrahOneDriveDesktop' 
[array] $Desk = (Get-ChildItem -LiteralPath $dir -Filter deskt*).FullName
[array] $VA = (Get-ChildItem -LiteralPath $dir -Filter *v*).FullName

[pscustomobject] @{
  DesktopLocation = $Desk
  DCount          = $Desk.Count
  VLocation       = $VA
  VCount          = $VA.Count
}
 

Комментарии:

1. Exception calling "Add" with "1" argument(s): "Collection was of a fixed size." Это ошибка, которую я получаю при попытке запустить первый блок кода, второй работает нормально, но я не уверен, почему первый выполняет.

2. Честно говоря, я просто хотел поработать, switch чтобы увидеть все, что он может сделать. Я знаю, что я мог бы сделать это, как 6 разных способов сделать это, но пытался немного поэкспериментировать. Действительно пытался применить этот новый метод к запросу AD для пользователей с определенными словами в их имени.

3. Понял, @AbrahamZinala. Что касается сообщения об ошибке: это означает, что вы использовали массив , а не [System.Collections.Generic.List[string]] экземпляр, как показано в первом фрагменте. Массивы представляют собой коллекции фиксированного размера, но поскольку они также реализуют System.Collections.IList интерфейс, у них есть .Add() метод, который всегда завершается ошибкой.

4. Есть ли что-нибудь, что вы рекомендуете мне изучить, чтобы изучить такие вещи? Книги, видео, форумы? Кажется, вы это хорошо понимаете

5. @zett42: Я никогда особо не изучал реализацию, но я думаю , что an ArrayList , который эффективно растет, используется за кулисами, а затем преобразуется в массив. Несколько связанное обсуждение на GitHub . Если вы хотите поэкспериментировать с относительной производительностью: $a = 1..1e6; Time-Command { $l = [System.Collections.Generic.List[object]] @(); foreach ($e in $a) { $l.Add($e) } }, { $l = foreach ($e in $a) { $e } }

Ответ №2:

Вам не нужен switch foreach цикл или, чтобы подсчитать, сколько файлов соответствует каждому имеющемуся у вас шаблону:

 # Fetch files
$gc = Get-ChildItem -Path 'C:usersabrahOneDriveDesktop'  

# Count those starting with "Deskt"
$desktopFiles = $gc |Where-Object Name -like "Deskt*"

# Count those matching `*v*`
$vFiles = $gc |Where-Object Name -like "*v*"

# Output details
[PSCustomObject]@{
  DesktopLocations = @($desktopFiles.FullName)
  DesktopCount     = $desktopFiles.Count
  VLocations       = @($vFiles.FullName)
  VCount           = $vFiles.Count
}
 

Комментарии:

1. спасибо за комментарий! Просто хотел поработать, switch чтобы посмотреть, что все это может сделать.

Ответ №3:

Другое решение:

 $Grouped=Get-ChildItem -Path 'C:usersabrahOneDriveDesktop'  -file | %{

if ($_.Name -like "Deskt*")
{
    Add-Member -InputObject $_ -MemberType NoteProperty -Name "TypeFile" -Value "DESK_FILE"
}
elseif ($_.Name -like "*v*")
{
   Add-Member -InputObject $_ -MemberType NoteProperty -Name "TypeFile" -Value "V_FILE"
}
else
{
   Add-Member -InputObject $_ -MemberType NoteProperty -Name "TypeFile" -Value "OTHER_FILE"
}

$_

} | Group TypeFile -AsHashTable

#result
$Grouped

#if you want files for a group 
$Grouped["V_FILE"] 

#if you want really your result
[PSCustomObject]@{
  DesktopLocations = $Grouped["DESK_FILE"].fullName 
  DesktopCount     = $Grouped["DESK_FILE"].Count
  VLocations       = $Grouped["V_FILE"].fullName 
  VCount           = $Grouped["V_FILE"].Count
}