Имя пользователя:
Пароль:  
Помощь | Регистрация | Забыли пароль?  | Правила  

Компьютерный форум OSzone.net » Программирование, базы данных и автоматизация действий » Скриптовые языки администрирования Windows » PowerShell - Выбор групп строк из массива по разделителю

Ответить
Настройки темы
PowerShell - Выбор групп строк из массива по разделителю

Новый участник


Сообщения: 25
Благодарности: 0

Профиль | Отправить PM | Цитировать


Добрый день. Имеется массив строк
Код: Выделить весь код
$mass1 = @(0,1,2,3,0,4,0,5,6)
В нем есть т.к. разделители групп данных, в данном случае это '0'
Задача:
Выделить эти группы данных для дальнейшей работы в отдельный двумерный массив или хеш-таблицу
В итоге должно получиться аналогично этой структуре
Код: Выделить весь код
$mass2 = @(@(1,2,3),@(4),@(5,6))
split тут не поможет так понимаю...
Пока только такая идея - использовать функцию для поиска индексов этого разделителя

Код: Выделить весь код
function findinarr ($mass, $value) {
    for ($i=0; $i -lt $mass.count;$i++) {
        if($mass[$i] -eq $value){$i}
    }
}
С ней можно получить кол-во и индексы вхождений '0'. В данном случае
Код: Выделить весь код
(findinarr $mass 0)
0
4
6
А потом как-то прогнать исходный массив, с выбором строк 0-3, 4-5 и передать это в новый массив. А Затем уже в нем split сделать окончательный
Как-то неуклюже.. и затратно будет, при наличии большого кол-ва строк
Есть какой-то "правильный" и оптимальный способ решения?

Отправлено: 21:24, 16-02-2023

 

Ветеран


Сообщения: 1754
Благодарности: 965

Профиль | Цитировать


Кривовато, но вроде работает:

Код: Выделить весь код
$mass = @(0,1,2,3,0,4,0,5,6)

$new = ($mass -join ';' -split ';?0;' | Group-Object { $_ -ne 0 }).Group |
    Where-Object { $_ -match '.' }
$newmass = New-Object 'array[]' $new.Count

for ($i = 0; $i -lt $new.Count; $i++) { $newmass[$i] = $new[$i].Split(';') }

$newmass[0]
$newmass[2]
$newmass[1]
Это сообщение посчитали полезным следующие участники:

Отправлено: 23:30, 16-02-2023 | #2



Для отключения данного рекламного блока вам необходимо зарегистрироваться или войти с учетной записью социальной сети.

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


Новый участник


Сообщения: 25
Благодарности: 0

Профиль | Отправить PM | Цитировать


Понятно, спасибо.
Была мысль собрать -join.
А если там будет условно 100 000 строк... Могут быть проблемы с производительностью

Отправлено: 00:33, 17-02-2023 | #3


Аватара для DJ Mogarych

fascinating rhythm


Moderator


Сообщения: 6530
Благодарности: 1483

Профиль | Отправить PM | Цитировать


Может, так?
Код: Выделить весь код
$mass2 = [System.Collections.ArrayList]@()
-join $mass1 -split '0' -match '.' |% {
    $mass2.add(("$_").ToCharArray())
}
Код: Выделить весь код
PS C:\WINDOWS\system32> $mass2.GetType()

IsPublic IsSerial Name                                     BaseType                                                                               
-------- -------- ----                                     --------                                                                               
True     True     ArrayList                                System.Object 

PS C:\WINDOWS\system32> $mass2[0]
1
2
3

PS C:\WINDOWS\system32> $mass2[0].GetType()

IsPublic IsSerial Name                                     BaseType                                                                               
-------- -------- ----                                     --------                                                                               
True     True     Char[]                                   System.Array

-------
Powershell 7.x | Powershell 5.1 | ffmpeg (docs)

Это сообщение посчитали полезным следующие участники:

Отправлено: 09:13, 17-02-2023 | #4


Аватара для YuS_2

Crazy


Contributor


Сообщения: 1182
Благодарности: 491

Профиль | Отправить PM | Цитировать


Код: Выделить весь код
$arr = @(0,1,2,3,0,4,0,5,6)
$a,$b,$cnt = @(),@(),0
$arr.foreach{
	switch ($_){
		0 {if ($cnt){$b += ,$a;$a = @()}}
		default {$a += $_}
	}
	$cnt++
	if($_ -and $arr.count -eq $cnt){$b += ,$a}
}
$b.count
$b

-------
scio me nihil scire. Ѫ


Отправлено: 11:05, 17-02-2023 | #5


Аватара для YuS_2

Crazy


Contributor


Сообщения: 1182
Благодарности: 491

Профиль | Отправить PM | Цитировать


Цитата ntdll.dll:
можно в detonate-выражение перевести »
слишком частное решение... массив не обязан начинаться с "0", подкорректировать требуется

-------
scio me nihil scire. Ѫ


Отправлено: 12:35, 17-02-2023 | #6


Аватара для YuS_2

Crazy


Contributor


Сообщения: 1182
Благодарности: 491

Профиль | Отправить PM | Цитировать


Цитата ntdll.dll:
Не менее частно »
Это каким-то образом влияет на частность в Вашем решении?
Тем более, что поправить - не проблема же.
Но там ещё есть другая проблема... при значительном увеличении количества элементов массива (точное число не назову, но на 10000 уже спотыкается ), метод с заменой регулярками попросту захлебнется от этого количества...
А вот метод со списками, вполне быстрый...

Цитата ntdll.dll:
если судить »
А здесь никто никого не судит...

Цитата ntdll.dll:
объективно »
А с этим вообще беда, т.к. объективность - труднодостижима... если только с этим на суд божий... да и то вряд ли...

Цитата ntdll.dll:
Самое вменяемое решение, как с позиции логики, так и производительности, мной озвучено: динамический метод+указатель+нуль-терминатор »
Указатели, нуль-терминаторы... речь точно о powershell?
Да и просто озвучивание - ничего не показывает... важно только решение, но где оно?

-------
scio me nihil scire. Ѫ


Отправлено: 17:24, 17-02-2023 | #7


Аватара для YuS_2

Crazy


Contributor


Сообщения: 1182
Благодарности: 491

Профиль | Отправить PM | Цитировать


Цитата solonenko:
100 000 строк... Могут быть проблемы с производительностью »
Вряд ли... см. ниже тесты.
Цитата ntdll.dll:
Самое вменяемое решение, как с позиции логики »
Ок, пока нет самого вменяемого решения... вот различные способы с измерением скорострельности:
Код: Выделить весь код
# тесты различных способов разделения массива по разделителю
# namespace - для использования варианта с list:
using namespace System.Collections.Generic

$splt = "0"
#$arr = @(0,0,0,1,22,33,0,0,0,444,555,550,606,0,44,55,0,1,2,3,4,5,0,8,9,0)
$arr = @(0,0,0)
$arr += 1..100000|%{get-random -min 0 -max 100}

write-host Вариант с replace, split и for -for cyan
measure-command{
$tmp = [string]$arr
while ($tmp[0] -match " |$splt" -or $tmp[-1] -match " |splt"){
	$tmp = $tmp.trim($splt).trim()
}
$a = $tmp -replace " ($splt )+"," $splt " -split " $splt "
$b = @()
for ($i=0;$i -lt $a.count;$i++){
	$b += ,[int[]](($a[$i].trim() -split' ').foreach{[int]"$_"})
}
}
write-host Кол-во элементов: $($b.count) -for green
write-host Первый элемент: $($b[0]) -for red
"===="

write-host Вариант с replace и iex -for cyan
measure-command{
$tmp = [string]$arr
while ($tmp[0] -match " |$splt" -or $tmp[-1] -match " |$splt"){
	$tmp = $tmp.trim($splt).trim()
}
#$b = iex "@($(($$="$a 0" -replace '(?:\s)?\b0\b(?:\s)?', '),(').Substring(2,$$.Length-4) -replace '\s', ','))"
$b = iex "@($((('('+$tmp+')') -replace "\s($splt\s)+",'),(') -replace '\s',','))"
}
write-host Кол-во элементов: $($b.count) -for green
write-host Первый элемент: $($b[0]) -for red
"===="

write-host Вариант с replace и скриптблоком -for cyan
measure-command{
$tmp = [string]$arr
while ($tmp[0] -match " |$splt" -or $tmp[-1] -match " |splt"){
	$tmp = $tmp.trim($splt).trim()
}
$b = &([scriptblock]::create([string]$((('('+$tmp+')') -replace " ($splt )+",'),(') -replace ' ',',')))
}
write-host Кол-во элементов: $($b.count) -for green
write-host Первый элемент: $($b[0]) -for red
"===="

write-host Вариант с foreach, switch и array -for cyan
measure-command{
$a,$b,$cnt = @(),@(),0
$arr.foreach{
	switch ($_){
		$splt {if ($cnt -and $t -ne $splt){$b += ,$a;$a = @()}}
		default {$a += $_}
	}
	$cnt++
	$t = $_
	if($_ -and $arr.count -eq $cnt){$b += ,$a}
}
}
write-host Кол-во элементов: $($b.count) -for green
write-host Первый элемент: $($b[0]) -for red
"===="

write-host Вариант с foreach и list -for cyan
measure-command{
$res, $tmp =[List[Int32[]]]::new(),[List[Int32]]::new()
foreach ($val in $arr) {
  if ($tmp -and $val -eq $splt -and $z -ne $splt) {
    $res.Add($tmp.ToArray())
    $tmp.Clear()
    #continue
  } elseif ($val -ne $splt){$tmp.Add($val)}
  $z = $val
}
if ($tmp){$res.Add($tmp.ToArray())}
#if (!$res[0]) {[void]$res.Remove($res[0])}
$res = $res.ToArray()
}
write-host Кол-во элементов: $($res.count) -for green
write-host Первый элемент: $($res[0]) -for red
"===="
Примеры кода, взятые из топика подвергались изменению, т.к. на различных тестах массивов выявлялись недочеты, в общем код приведен к общему знаменателю...
Изначально формируется один массив в 100000 элементов, причем на все варианты - результаты идентичны, но скорострельность отличается...

-------
scio me nihil scire. Ѫ


Последний раз редактировалось YuS_2, 18-02-2023 в 13:57.

Это сообщение посчитали полезным следующие участники:

Отправлено: 13:52, 18-02-2023 | #8


Аватара для DJ Mogarych

fascinating rhythm


Moderator


Сообщения: 6530
Благодарности: 1483

Профиль | Отправить PM | Цитировать


+=, кстати - довольно коварная штука. По умолчанию массив в PS неизменяемый (immutable), поэтому при += создаётся новый массив. Если элементов много, то падение производительности после определённого кол-ва элементов становится очень большим.

Есть ArrayList, который изменяемый и в него можно именно добавлять элементы, а не пересоздавать массив каждый раз.

https://adamtheautomator.com/powersh...ith_PowerShell

-------
Powershell 7.x | Powershell 5.1 | ffmpeg (docs)

Это сообщение посчитали полезным следующие участники:

Отправлено: 14:29, 18-02-2023 | #9


Аватара для YuS_2

Crazy


Contributor


Сообщения: 1182
Благодарности: 491

Профиль | Отправить PM | Цитировать


Цитата DJ Mogarych:
поэтому при += создаётся новый массив. »
Это да, есть такой момент. На больших значениях количества элементов, очень заметно это...
У меня тут даже тест есть...
Код: Выделить весь код
$cnt = 30000

measure-command{
$arr1 = @()
for ($i=0;$i -le $cnt;$i++) {
	$arr1 += "test $i"
}
}

measure-command{
$arr2 = new-object system.collections.generic.list[system.string]
for ($i=0;$i -le $cnt;$i++) {
	$arr2.add("test $i")
}
}

measure-command {
$arr3 = new-object system.text.stringbuilder
for ($i=0;$i -le $cnt;$i++){
	$null = $arr3.append("test $i")
}
}
Но в данном случае, количество получаемых элементов для приращения массива не столь велико, чтобы оказывать существенное влияние на скорость... в тестах разделения массивов это видно, там есть вариант с коллекцией типа List, это по скорости почти то же самое...
Хотя, почему бы не использовать, раз уж есть такой тип массивов... в любом случае, хоть и ненамного, но быстрее.

-------
scio me nihil scire. Ѫ


Отправлено: 14:45, 18-02-2023 | #10



Компьютерный форум OSzone.net » Программирование, базы данных и автоматизация действий » Скриптовые языки администрирования Windows » PowerShell - Выбор групп строк из массива по разделителю

Участник сейчас на форуме Участник сейчас на форуме Участник вне форума Участник вне форума Автор темы Автор темы Шапка темы Сообщение прикреплено

Похожие темы
Название темы Автор Информация о форуме Ответов Последнее сообщение
CMD/BAT - [решено] Разбить txt на части по разделителю Viktor99 Скриптовые языки администрирования Windows 7 31-07-2022 15:13
C/C++ - [решено] Удаление строк динамического массива alexprom65 Программирование и базы данных 1 24-12-2014 22:47
CMD/BAT - Выбор данных из массива. subuday77 Скриптовые языки администрирования Windows 1 25-12-2013 06:13
[решено] Вывод массива строк в одном окне сообщения (MsgBox) support23 AutoIt 4 29-10-2012 18:26
С/С++ | Выбор 10 случайных элементов из массива Vovius Программирование и базы данных 5 29-08-2006 19:37




 
Переход