Удаление строк, если подстрока строки присутствует в том же массиве - PullRequest
0 голосов
/ 22 мая 2018

Noob здесь.

Я пытаюсь сократить список доменов, удалив все поддомены, если родительский домен присутствует в списке.Мне удалось собрать воедино скрипт, который в некоторой степени делает это с PowerShell после некоторого поиска и чтения.Вывод не совсем то, что я хочу, но будет работать нормально.Проблема с моим решением состоит в том, что он занимает много времени из-за размера моего начального списка (десятки тысяч записей).

ОБНОВЛЕНИЕ: я обновил мой пример, чтобы уточнить мой вопрос.

Пример списка «parent.txt»:

adk2.co
adk2.com
adobe.com
helpx.adobe.com
manage.com
list-manage.com
graph.facebook.com

Пример вывода файла «repeatats.txt»:

adk2.com (different top level domain than adk2.co but that's ok)
helpx.adobe.com
list-manage.com (not subdomain of manage.com but that's ok)

Затем я бы взял и исключил повторы из родительского, оставив список «уникальных» поддоменов и доменов.У меня есть это в отдельном сценарии.

Пример окончательного списка с моим текущим сценарием:

adk2.co    
adobe.com
manage.com
graph.facebook.com (it's not facebook.com because facebook.com wasn't in the original list.)

Идеальный окончательный список:

adk2.co
adk2.com (since adk2.co and adk2.com are actually distinct domains)
adobe.com
manage.com
graph.facebook.com

Ниже мойcode:

Я взял свой список хостов (parent.txt), проверил его на предмет соответствия и выложил любые совпадения в новый файл.

$parent = Get-Content("parent.txt")
$hosts = Get-Content("parent.txt")
$repeats =@()

$out_file     = "$PSScriptRoot\repeats.txt"

$hosts | where { 
    $found = $FALSE
    foreach($domains in $parent){
        if($_.Contains($domains) -and $_ -ne $domains){
            $found = $TRUE
            $repeats += $_
        }
        if($found -eq $TRUE){
            break
        }
    }
    $found
}

$repeats     = $repeats -join "`n"

[System.IO.File]::WriteAllText($out_file,$repeats)

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

Ответы [ 2 ]

0 голосов
/ 23 мая 2018

Во-первых, решение , основанное строго на общих именах доменов (например, helpx.adobe.com и adobe.com считаются принадлежащими одному и тому же домену, а list-manage.com и manage.com - нет).Это не то, что вы просили, но, возможно, более полезно для будущих читателей:

Get-Content parent.txt | Sort-Object -Unique { ($_ -split '\.')[-2,-1] -join '.' }

Предполагая list.manage.com вместо list-manage.com в вашем примере ввода, приведенная выше команда дает:

adk2.co
adk2.com
adobe.com
graph.facebook.com
manage.com
  • { ($_ -split '\.')[-2,-1] -join '.' } сортирует строки ввода по двум последним компонентам домена (например, adobe.com):

  • -Unique удаляет дубликаты.


A решение с общим суффиксом , по запросу:

# Helper function for (naively) reversing a string.
# Note: Does not work properly with Unicode combining characters
#       and surrogate pairs.
function reverse($str) { $a = $str.ToCharArray(); [Array]::Reverse($a); -join $a }

# * Sort the reversed input lines, which effectively groups them by shared suffix
#   with the shortest entry first (e.g., the reverse of 'manage.com' before the
#   reverse of 'list-manage.com').
# * It is then sufficient to output only the first entry in each group, using
#   wildcard matching with -notlike to determine group boundaries.
# * Finally, sort the re-reversed results.
Get-Content parent.txt | ForEach-Object { reverse $_ } | Sort-Object |
  ForEach-Object { $prev = $null } {
    if ($null -eq $prev -or $_ -notlike "$prev*" ) { 
      reverse $_ 
      $prev = $_
    }
  } | Sort-Object
0 голосов
/ 23 мая 2018

Один из подходов заключается в использовании хеш-таблицы для хранения всех ваших значений parent, а затем для каждого repeat удалите его из таблицы.Значение 1 при добавлении в хеш-таблицу не имеет значения, поскольку мы проверяем только наличие ключа.

$parent = @(
'adk2.co',
'adk2.com',
'adobe.com',
'helpx.adobe.com',
'manage.com',
'list-manage.com'
)

$repeats = (
'adk2.com',
'helpx.adobe.com',
'list-manage.com'
)

$domains = @{}
$parent | % {$domains.Add($_, 1)}
$repeats | % {if ($domains.ContainsKey($_)) {$domains.Remove($_)}}

$domains.Keys | Sort
...