У меня есть 2 набора данных. Set1 имеет примерно 129 тыс. строк, имеет столбец ID и, что немаловажно, код второго столбца, который мне понадобится позже. Set2 имеет только столбец ID. Set2 также содержит около 83 тысяч строк, и все они должны находиться в Set1. Оба файла/набора данных должны быть упорядочены по идентификатору, если это имеет значение. Оба должны быть строками, но все идентификаторы дополняются до 10 цифр.
ID,Code
0000000002,0
0000012345,1
0000023456,0
0000056789,1
0000034567,0
0000078908,1
0000000002
0000012345
0000056789
0000034567
Я пытаюсь найти все идентификаторы в наборе 1, которых нет в наборе 2, включая этот второй столбец для каждого идентификатора из набора данных 1. Мне также нужны все идентификаторы в наборе 1, которые находятся в наборе 2, включая этот второй столбец для каждого идентификатора.
Мне также нужны подмножества для каждого из них:
Все идентификаторы в наборе 1, которых нет в наборе 2, включая этот столбец кода, разделенные кодом 0,1,2.
Все идентификаторы в наборе Set1, которые находятся в наборе Set2, включая этот столбец кода, разделенные кодом 0,1,2.
Основные проблемы, с которыми я сталкиваюсь, заключаются в том, что наборы данных не совпадают: в основном наборе данных есть 2 столбца, а в наборе сравниваемых данных - только 1. И тот факт, что наборы данных настолько велики, что я пытаюсь сделать это эффективно, поэтому это не займет много времени, поскольку это ежедневная программа, и после того, как я получу эти списки подмножеств, нужно будет запустить и другие вещи.
Я пытался импортировать массивы и сравнивать их, чтобы получить нужные мне наборы данных, но это занимает слишком много времени, чтобы быть практичным. Я говорю примерно 1 час+. это даже не доходит до того, что мне нужно подмножество их на основе 2-го столбца.
$IDsNotIn2 = $Array1 | Where {$Array2 -NotContains $_}
Я пытался использовать хеш-таблицы, но не смог заставить сравнения работать. Я импортировал CSV как хэш-таблицы. Затем называется Compare-Object. Ничего не вернули/ничего не показали при звонке.
import-CSV -Path $FILE_LOC | ForEach-Object { $hashtable1[$_.ID] = $_.Code }
import-CSV -Path $FIXED_FILE_LOC -Header ID | ForEach-Object { $hashtable2[$_.ID] }
Compare-Object -ReferenceObject $hashtable1 -DifferenceObject $hashtable2 -Property ID -PassThru | ? {$_.SideIndicator -eq "< = "} | Select-Object -Property * -ExcludeProperty SideIndicator
Compare-Object -ReferenceObject $hashtable1 -DifferenceObject $hashtable2
Я попробовал .GetEnumerator и перебрал первую хеш-таблицу, и если ключ существует во второй, создал третью таблицу с новыми значениями. Но по какой-то причине все значения из первой таблицы помещаются в новую таблицу.
$hashtable1.GetEnumerator() | ForEach-Object {
IF (-Not ($hashtable2.ContainsKey($_.key))){
$ID = $_.key
$columncode = $_.value
$ID_Not_in_First_File[$ID] = @{
$Code= $columncode
}
}
}
Я не могу привести буквальную выборку своих наборов данных, нет. Наборы данных точно такие же, как мой образец, который я включил в вопрос OG. Набор данных 1 — это CSV-файл с заголовками, такими как идентификатор, код, но в остальном он точно такой, как я туда вставил. 10-значные числа, запятая, а затем 0,1,2. Набор данных 2 представляет собой буквально 10-значное число в строке, без заголовков.
да, теперь ясно, я имел в виду, что в вашем вопросе есть Set1=
и Set2=
, а затем в каждой строке есть пробелы, и я предполагаю, что это не так (пробелов нет). Это сбивает с толку читателей вашего вопроса.
Хорошо, теперь я понимаю. Я использовал это как псевдокод, который на самом деле не означает ничего, кроме идентификации множеств. Я изменил это.
В общем, я бы сделал хеш-таблицу одного из списков.
Я пытался хешировать оба списка и сравнивать их. Но решение, которое предложил Сантьяго, заключалось в том, чтобы хешировать одно и перебирать другое, что помогло мне, и я смог использовать это для решения своей проблемы. Спасибо.
Если я правильно понимаю, эффективным решением может быть следующее:
$mapNotInSet2 = @{}
$mapInSet2 = @{}
$rowsNotInSet2 = [System.Collections.Generic.List[object]]::new()
# NOTE: Use absolute path to the file here,
# don't use relative path when calling a .NET method
$set2 = [System.Collections.Generic.HashSet[string]]::new(
[System.IO.File]::ReadLines('path\to\set2.txt'))
$rowsInSet2 = foreach ($row in Import-Csv 'path\to\set1.csv') {
# Id exists in Set 2
if ($set2.Contains($row.Id)) {
if (-not $mapInSet2.ContainsKey($row.Id)) {
$mapInSet2[$row.Id] = [System.Collections.Generic.List[string]]::new()
}
$mapInSet2[$row.Id].Add($row.code)
$row
continue
}
# else, Id does not exist in Set 2
if (-not $mapNotInSet2.ContainsKey($row.Id)) {
$mapNotInSet2[$row.Id] = [System.Collections.Generic.List[string]]::new()
}
$mapNotInSet2[$row.Id].Add($row.code)
$rowsNotInSet2.Add($row)
}
$rowsInSet2
Это даст 4 различных результата, используя образцы данных:
$rowsInSet2
ID code
-- ----
0000000002 0
0000012345 1
0000012345 2
0000056789 1
0000034567 0
$mapInSet2
(подмножество, уникальные идентификаторы с соответствующими code
)Name Value
---- -----
0000034567 {0}
0000012345 {1, 2}
0000056789 {1}
0000000002 {0}
$rowsNotInSet2
ID code
-- ----
0000023456 0
0000078908 1
$mapNotInSet2
(подмножество, уникальные идентификаторы с соответствующими code
)Name Value
---- -----
0000078908 {1}
0000023456 {0}
Спасибо за помощь. Я обнаружил одну ошибку в своем образце набора данных. Все идентификаторы должны быть уникальными в обоих списках. экв. В наборе 1 не должно быть 2 0000012345. Кроме того, я проверил ваш код и получил ошибку: if (-not $mapInSet2.ContainsKey($row.Id)) «Ключ не может быть нулевым», а также по адресу: $mapNotInSet2 [$row.Id].Add($row.code) "индекс массива имеет нулевое значение". У меня есть скриншот ошибки, но я не знаю, как его сюда разместить.
Я просто запустил еще раз и поставил $row для печати прямо перед оператором if в foreach, и он ничего не распечатал. Я изменил его на «Write-Output $row», и ничего не распечаталось. Я не уверен, почему он пуст. Я использую локальные файлы и даже жестко запрограммировал прямой путь «C:\Temp\Z\имя_файла». Раньше я использовал import-csv для этого файла, и он работал нормально.
Спасибо за помощь. Я обнаружил, что могу читать список set1 и перебирать его как обычно. Это исправило проблему, которую я видел. Это очень помогло. Еще раз спасибо.
Можете ли вы отредактировать копию вопроса, вставив буквальный образец обоих наборов, включая заголовки, если они есть?