programing

2개의 어레이를 비교하여 일반적이지 않은 값을 취득하다

batch 2023. 4. 11. 21:51
반응형

2개의 어레이를 비교하여 일반적이지 않은 값을 취득하다

두 어레이의 내용을 비교하고 powershell을 사용하여 공통적이지 않은 값을 얻을 수 있는 작은 논리를 원했습니다.

예를 들면

$a1=@(1,2,3,4,5)
$b1=@(1,2,3,4,5,6)

$c, 즉 출력은 "의 값을 얻을 수 있습니다.6두 어레이 간의 일반적인 가치를 나타내는 출력입니다.

누가 나 좀 도와줄래! 고마워!

PS > $c = Compare-Object -ReferenceObject (1..5) -DifferenceObject (1..6) -PassThru
PS > $c
6

수집

$a = 1..5
$b = 4..8

$Yellow = $a | Where {$b -NotContains $_}

$Yellow 의 모든 항목이 포함되어 있습니다.$a안에 있는 것들만 빼고$b:

PS C:\> $Yellow
1
2
3

$Blue = $b | Where {$a -NotContains $_}

$Blue 의 모든 항목이 포함되어 있습니다.$b안에 있는 것들만 빼고$a:

PS C:\> $Blue
6
7
8

$Green = $a | Where {$b -Contains $_}

문제 없습니다만, 어쨌든, 양쪽 모두에 포함되는 아이템이 포함되어 있습니다.$a그리고.$b.

PS C:\> $Green
4
5

주의:Where의 에일리어스입니다.Where-Object. 에일리어스로 인해 발생할 수 있는 문제가 발생하여 스크립트를 유지보수가 어려워질 수 있습니다.


2019년 10월 12일 부록

@xtreampb 및 @mklement0에 의해 코멘트된 바와 같이 질문의 예에서는 표시되지 않지만 질문에 포함된 태스크('공통하지 않은 값')는 두 입력 세트 간의 대칭 차이입니다(노란색과 파란색의 결합).

유니언

의 대칭적 차이$a그리고.$b문자 그대로의 결합이라고 정의할 수 있다$Yellow그리고.$Blue:

$NotGreen = $Yellow + $Blue

다음과 같이 기술되어 있습니다.

$NotGreen = ($a | Where {$b -NotContains $_}) + ($b | Where {$a -NotContains $_})

성능

아시다시피 이 구문에는 상당히 많은 (용장) 루프가 있습니다.목록의 모든 항목$a반복(사용)Where)에서 목록 항목까지$b(사용)-NotContains) 및 비자(visa)도 마찬가지입니다.유감스럽게도 양측의 결과를 예측하기 어렵기 때문에 중복을 피하기 어렵다.해시 테이블은 보통 다중 루프의 성능을 향상시키는 데 적합한 솔루션입니다.이를 위해 저는 다음과 같은 질문을 재정의하고 싶습니다.컬렉션 합계에 한 번 표시되는 값을 가져옵니다().$a + $b

$Count = @{}
$a + $b | ForEach-Object {$Count[$_] += 1}
$Count.Keys | Where-Object {$Count[$_] -eq 1}

를 사용하여ForEach스테이트먼트 대신ForEach-Objectcmdlet 및Where대신 메서드Where-Object성능을 2.5배 높일 수 있습니다.

$Count = @{}
ForEach ($Item in $a + $b) {$Count[$Item] += 1}
$Count.Keys.Where({$Count[$_] -eq 1})

LINQ

단, Language Integrated Query(LINQ)는 어떤 네이티브 PowerShell 및 네이티브를 능가합니다.넷 메서드(LINQ를 탑재한 고성능 PowerShell 및 mklement0의 "다음 네스트된 포어치 루프는 PowerShell에서 심플화할 수 있습니까?"에 대한 답변도 참조하십시오.

LINQ를 사용하려면 어레이 유형을 명시적으로 정의해야 합니다.

[Int[]]$a = 1..5
[Int[]]$b = 4..8

또,[Linq.Enumerable]::연산자:

$Yellow   = [Int[]][Linq.Enumerable]::Except($a, $b)
$Blue     = [Int[]][Linq.Enumerable]::Except($b, $a)
$Green    = [Int[]][Linq.Enumerable]::Intersect($a, $b)
$NotGreen = [Int[]]([Linq.Enumerable]::Except($a, $b) + [Linq.Enumerable]::Except($b, $a))

대칭 제외와 함께

(2022-05-02 추가)
클래스메서드를 사용하고 있는 대칭의 차이를 취득하는 다른 방법도 있습니다.상세한 것에 대하여는, 다음2개의 매우 큰 리스트로 무엇이 다른지를 참조해 주세요.

$a = [System.Collections.Generic.HashSet[int]](1..5)
$b = [System.Collections.Generic.HashSet[int]](4..8)

$a.SymmetricExceptWith($b)
$NotGreen = $a # note that the result will be stored back in $a

벤치마크

(2022-05-02 업데이트, @Santiago 벤치마크 스크립트 개선 감사합니다)
벤치마크 결과는 컬렉션의 크기와 실제로 공유되는 항목의 수에 따라 크게 달라집니다.또한 LINQ와 마찬가지로 지연된 평가(지연된 실행이라고도 함)를 사용하는 방법에 대한 결론을 도출하는 경고도 있습니다.SymmetricExceptWith 결과@($a)[0])는 식을 평가하기 위해 수행되어야 할 작업을 정의하는 것 외에 아직 수행되지 않았기 때문에 예상보다 오랜 시간이 걸릴 수 있습니다.다음 항목도 참조하십시오.배열 속성에서 고유 인덱스 항목을 가져오는 가장 빠른 방법
어쨌든, 「평균」으로서 각 컬렉션의 절반은 다른 컬렉션과 공유되고 있는 것을 상정하고 있습니다.

Test           TotalMilliseconds
----           -----------------
Compare-Object          118.5942
Where-Object            275.6602
ForEach-Object           52.8875
foreach                  25.7626
Linq                     14.2044
SymmetricExce…            7.6329

성능을 제대로 비교하려면 새로운 PowerShell 세션을 시작하는 등의 방법으로 캐시를 지워야 합니다.

[Int[]]$arrA = 1..1000
[Int[]]$arrB = 500..1500

Measure-Command {&{
    $a = $arrA
    $b = $arrB
    Compare-Object -ReferenceObject $a -DifferenceObject $b  -PassThru
}} |Select-Object @{N='Test';E={'Compare-Object'}}, TotalMilliseconds
Measure-Command {&{
    $a = $arrA
    $b = $arrB
    ($a | Where {$b -NotContains $_}), ($b | Where {$a -NotContains $_})
}} |Select-Object @{N='Test';E={'Where-Object'}}, TotalMilliseconds
Measure-Command {&{
    $a = $arrA
    $b = $arrB
    $Count = @{}
    $a + $b | ForEach-Object {$Count[$_] += 1}
    $Count.Keys | Where-Object {$Count[$_] -eq 1}
}} |Select-Object @{N='Test';E={'ForEach-Object'}}, TotalMilliseconds
Measure-Command {&{
    $a = $arrA
    $b = $arrB
    $Count = @{}
    ForEach ($Item in $a + $b) {$Count[$Item] += 1}
    $Count.Keys.Where({$Count[$_] -eq 1}) # => should be foreach($key in $Count.Keys) {if($Count[$key] -eq 1) { $key }} for fairness
}} |Select-Object @{N='Test';E={'foreach'}}, TotalMilliseconds
Measure-Command {&{
    $a = $arrA
    $b = $arrB
    [Int[]]([Linq.Enumerable]::Except($a, $b) + [Linq.Enumerable]::Except($b, $a))
}} |Select-Object @{N='Test';E={'Linq'}}, TotalMilliseconds
Measure-Command {&{
    $a = $arrA
    $b = $arrB
    ($r = [System.Collections.Generic.HashSet[int]]::new($a)).SymmetricExceptWith($b)
}} |Select-Object @{N='Test';E={'SymmetricExceptWith'}}, TotalMilliseconds

Compare-Object

Compare-Object $a1 $b1 | ForEach-Object { $_.InputObject }

오브젝트가 어디에 속해 있는지 알고 싶다면 SideIndicator를 참조하십시오.

$a1=@(1,2,3,4,5,8)
$b1=@(1,2,3,4,5,6)
Compare-Object $a1 $b1

시험:

$a1=@(1,2,3,4,5)
$b1=@(1,2,3,4,5,6)
(Compare-Object $a1 $b1).InputObject

또는 다음을 사용할 수 있습니다.

(Compare-Object $b1 $a1).InputObject

순서는 중요하지 않아요.

어레이를 먼저 정렬하지 않으면 결과는 도움이 되지 않습니다.배열을 정렬하려면 Sort-Object를 통해 배열을 실행합니다.

$x = @(5,1,4,2,3)
$y = @(2,4,6,1,3,5)

Compare-Object -ReferenceObject ($x | Sort-Object) -DifferenceObject ($y | Sort-Object)

간단한 해시 테이블을 사용하면 도움이 될 것입니다.

$a1=@(1,2,3,4,5) $b1=@(1,2,3,4,5,6)


$hash= @{}

#storing elements of $a1 in hash
foreach ($i in $a1)
{$hash.Add($i, "present")}

#define blank array $c
$c = @()

#adding uncommon ones in second array to $c and removing common ones from hash
foreach($j in $b1)
{
if(!$hash.ContainsKey($j)){$c = $c+$j}
else {hash.Remove($j)}
}

#now hash is left with uncommon ones in first array, so add them to $c
foreach($k in $hash.keys)
{
$c = $c + $k
}

언급URL : https://stackoverflow.com/questions/6368386/comparing-two-arrays-get-the-values-which-are-not-common

반응형