【问题标题】:Efficient way to remove duplicates from large 2D arrays in PowerShell在 PowerShell 中从大型二维数组中删除重复项的有效方法
【发布时间】:2019-10-21 07:50:51
【问题描述】:

我有一大组数据,大约有 1000 万个项目,我需要根据六个列标题中的两个来高效、快速地删除重复项目。

我尝试过对项目进行分组和排序,但速度非常慢。

$p1 = $test | Group-Object -Property ComputerSeriaID,ComputerID 
    $p2 =  foreach ($object in $p1.group) { 
           $object | Sort-Object -Property FirstObserved | Select-Object -First 1
        }

我们的目标是通过评估两列来删除重复项,同时根据第一次观察来保持最旧的记录。

数据看起来像这样:

上次观察时间:2019-06-05T15:40:37 第一次观察:2019-06-03T20:29:01 计算机名称:1 计算机编号:2 虚拟:3 计算机序列号:4

上次观察时间:2019-06-05T15:40:37 第一次观察:2019-06-03T20:29:01 计算机名称:5 计算机编号:6 虚拟:7 计算机序列号:8

上次观察时间:2019-06-05T15:40:37 第一次观察:2019-06-03T20:29:01 计算机名称:9 计算机编号:10 虚拟:11 计算机序列号:12

【问题讨论】:

  • 请更改您的标题-您不是在谈论二维数组...您是在谈论要根据该数组中对象中的两个属性进行过滤的一维数组。 [咧嘴]
  • 老实说,有这么多项目,你为什么不使用真正的数据库来完成这项工作?我想你可以构建一个哈希表,并针对它执行查找,但与使用为处理大型数据集而构建的工具相比,这也会很慢。

标签: arrays powershell duplicates large-data


【解决方案1】:

您可能想稍微澄清一下您的问题,因为它有点难以阅读,但我会尽量用我能理解的关于您尝试做的事情来回答。

不幸的是,由于数据如此之多,我们无法快速做到这一点。字符串比较和排序是通过蛮力完成的;除了一次测量一个字符串以查看它们是否相同之外,没有办法降低将一个字符串中的每个字符与另一个字符进行比较的复杂性。

(老实说,如果是我,我只会在 excel 中使用 export-csv $object 和 perform this operation。仅编写一次此类脚本的时间折衷是不值得的。)

通过“项目”,我将假设您的意思是表中的行,并且您不会尝试仅检索您正在查找的行中的字符串。您已经掌握了 select-object down 的基本概念,您可以对整个表格执行此操作:

$outputFirstObserved = $inputData | Sort-Object -Property FirstObserved -Unique 
$outputLastObserved = $inputData | Sort-Object -Property LastObserved -Unique

现在您的内存中有大约 2000 万行,但我想这比手动操作要好。剩下的就是join the two tables。您可以使用Install-Script -Name Join 从 powershell 库下载该 Join-Object 命令,并按照描述的方式使用它。如果您想自己执行此步骤,最简单的方法是将两个表压缩在一起并再次排序:

$output = $outputFirstObserved + $outputLastObserved
$return = $output | Sort-Object | Get-Unique

【讨论】:

【解决方案2】:

这样做可以吗?它会保留最先找到的那个。

$test | sort -u ComputerSeriaID, ComputerID 

【讨论】:

    【解决方案3】:

    我创建了这个函数来对我的多维数组进行重复数据删除。 基本上,我连接记录的内容,将其添加到哈希中。 如果连接文本已存在于哈希中,则不要将其添加到要返回的数组中。

    Function DeDupe_Array
    {
    param
    (
    $Data
    )
    $Return_Array = @()
    $Check_Hash = @{}
    
    
    
    Foreach($Line in $Data)
        {
            $Concatenated = ''
    
            $Elements = ($Line | Get-Member -MemberType NoteProperty | % {"$($_.Name)"})
    
            foreach($Element in $Elements)
            {
                $Concatenated += $line.$Element
            }
    
            If($Check_Hash.$Concatenated -ne 1)
            {
                $Check_Hash.add($Concatenated,1)
                $Return_Array += $Line
            }
        }
    
    return $Return_Array
    }
    
    

    【讨论】:

      【解决方案4】:

      试试下面的脚本。

      应该尽可能快,因为要避免 PS 中的任何管道。

      $hashT = @{}
      foreach ($item in $csvData) {
          # Building hash table key
          $key = '{0}###{1}' -f $item.ComputerSeriaID, $item.ComputerID 
      
          # if $key doesn't exist yet OR when $key exists and "FirstObserverd" is less than existing one in $hashT (only valid when date provided in sortable format / international format)
          if ((! $hashT.ContainsKey($key)) -or ( $item.FirstObserved -lt $hashT[$key].FirstObserved )) {
              $hashT[$key] = $item
          }
      }
      $result = $hashT.Values 
      

      【讨论】:

        猜你喜欢
        • 2017-11-06
        • 1970-01-01
        • 2019-07-31
        • 2019-05-02
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多