сегментация списка значений - PullRequest
3 голосов
/ 28 марта 2011

Я пишу некоторый код, чтобы понять, как разбить список значений на более управляемые куски. причина, по которой я хочу это сделать, заключается в том, что у меня будет около 100 000 текущих значений, и я хочу минимизировать риск отказов.


$wholeList = 1..100

$nextStartingPoint

$workingList

function Get-NextTenItems()
{
    $workingList = (1+$nextStartingPoint)..(10+$nextStartingPoint)

    $nextStartingPoint += 10

    Write-Host "inside Get-NextTenItems"
    write-host "Next StartingPoint: $nextStartingPoint"
    $workingList
    Write-Host "exiting Get-NextTenItems"
}

function Write-ListItems()
{
    foreach ($li in $workingList)
    {
        Write-Host $li
    }
}
Get-NextTenItems
Write-ListItems
Get-NextTenItems
Write-ListItems

Я запустил код в отладчике PowerGUI и заметил, что моя $ nextStartingPoint сбрасывается в 0 при выходе из функции Get-NextTenItems.

Почему это происходит и как я могу предотвратить это?

Должен ли я также предположить, что то же самое происходит с $ workingList?

Ответы [ 3 ]

3 голосов
/ 28 марта 2011

Я предлагаю использовать трубопроводы. Одна функция производит куски, а другая потребляет их.

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

function Get-Chunk
{
    param(
        [Parameter(Mandatory=$true)]$collection, 
        [Parameter(Mandatory=$false)]$count=10
    )
    #temporary array
    $tmp = @()
    $i = 0
    foreach($c in $collection) {
        $tmp += $c                  # add item $c to array
        $i++                        # increase counter; indicates that we reached chunk size
        if ($i -eq $count) {
            ,$tmp                   # send the temporary array to the pipeline
            $i = 0                  # reset variables
            $tmp = @()         
        }
    }
    if ($tmp)  {                    # if there is something remaining, send it to the pipeline
        ,$tmp
    }
}

function Write-ListItems
{
    param(
        [Parameter(Mandatory=$true, ValueFromPipeline=$true)]$chunk
    )
    process {
        write-host Chunk: "$chunk"
    }
}

Проверка функций:

$wholeList = 1..100
Get-Chunk $wholeList | Write-ListItems
Chunk: 1 2 3 4 5 6 7 8 9 10
Chunk: 11 12 13 14 15 16 17 18 19 20
Chunk: 21 22 23 24 25 26 27 28 29 30
Chunk: 31 32 33 34 35 36 37 38 39 40
Chunk: 41 42 43 44 45 46 47 48 49 50
Chunk: 51 52 53 54 55 56 57 58 59 60
Chunk: 61 62 63 64 65 66 67 68 69 70
Chunk: 71 72 73 74 75 76 77 78 79 80
Chunk: 81 82 83 84 85 86 87 88 89 90
Chunk: 91 92 93 94 95 96 97 98 99 100

Get-Chunk $wholeList 32 | Write-ListItems
Chunk: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
Chunk: 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64
Chunk: 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96
Chunk: 97 98 99 100

Обновление

Я добавил несколько комментариев, чтобы прояснить ситуацию. Обратите внимание, что при отправке контента в конвейер (а) я не использую return, потому что я бы отскочил от функции. (b) запятая в начале оборачивает содержимое $tmp в массив, поэтому создает новый массив с одним элементом (который является массивом из N элементов). Зачем? Потому что в PowerShell есть автоматическое развертывание, которое развернет элементы из массива и сгладит все элементы -> в результате снова будет один большой массив.

Пример:

function Get-Arrays {
  1,2,3
  "a", "b"
  ,(get-date)
  4,5,6
}
Get-Arrays | % { "$_" }

Это работает как ожидалось:

function Get-Arrays {
  ,(1,2,3)
  ,("a", "b")
  ,(get-date)
  ,(4,5,6)
}
Get-Arrays | % { "$_" }
2 голосов
/ 28 марта 2011

В вашем примере Get-NextTenItems меняет локальные переменные.Есть несколько способов решить эту проблему, вот два из них:

1) Укажите области действия переменных явно (используйте префикс script или global).А именно, используйте эти переменные как $script:nextStartingPoint, $script:workingList внутри функции.

2) Измените область действия функции при ее вызове.А именно, вызовите функцию с помощью оператора точки (функция «точка-источник»), т.е. выполните ее в текущей области видимости.Этот код работает должным образом (другие изменения не требуются):

. Get-NextTenItems
Write-ListItems
. Get-NextTenItems
Write-ListItems 

См. Также

help about_scopes
1 голос
/ 28 марта 2011

Предыдущий ответ в порядке.Но он не полный, он позволяет вам как-то кодировать нечитабельно .С точки зрения чистого программирования, у вас есть два других способа передачи параметров в процедуру (или функцию), и один из этих способов позволяет вам изменять ваш параметр.

1.Параметры по значению (обычная мода)

, используя этот способ, вы документируете параметры, используемые вашей функцией

Function addition ([int]$x, [int]$y) {
  $x + $y
}

2.Параметры по аргументу (вызываемый по ссылке своего рода указателем)

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

function addition ([int]$x, [int]$y, [ref]$R) {
 $Res = $x * $y
 $R.value = $Res
}

# usage
addition $A $B ([ref]$C)

В вашем коде с использованием второгоРешение будет:

  1. Позволит вам изменить вашу переменную в функцию
  2. Дайте знать другим читателям функции, что эта функция может изменять один из ее параметров

Надеюсь, это поможет.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...