Создайте список элементов, общих для объектов

У меня есть эти источники данных. (Технически результат некоторых API звонков). Логика сопоставления Id равна, но обратите внимание, что они называются разными именами, поэтому Id и AlsoId, IdToo по сути одно и то же.

$data1 = @(
    [PSCustomObject]@{ Id='1'; Service='Service1'; Propertyx=1; Price='5' }
    [PSCustomObject]@{ Id='2'; Service='Service1'; Propertyx=1; Price='17' }
    [PSCustomObject]@{ Id='3'; Service='Service1'; Propertyx=1; Price='3' }
    [PSCustomObject]@{ Id='4'; Service='Service1'; Propertyx=1; Price='7' }
)

$data2 = @(
    [PSCustomObject]@{ AlsoId='1'; Service='Service1'; Propertyx=1; Price='5' }
    [PSCustomObject]@{ AlsoId='2'; Service='Service1'; Propertyx=1; Price='17' }
    [PSCustomObject]@{ AlsoId='5'; Service='Service1'; Propertyx=1; Price='3' }
    [PSCustomObject]@{ AlsoId='6'; Service='Service1'; Propertyx=1; Price='7' }
)

$data3 = @(
    [PSCustomObject]@{ IdToo='1'; Service='Service1'; Propertyx=1; Price='5' }
    [PSCustomObject]@{ IdToo='2'; Service='Service1'; Propertyx=1; Price='17' }
    [PSCustomObject]@{ IdToo='5'; Service='Service1'; Propertyx=1; Price='3' }
    [PSCustomObject]@{ IdToo='7'; Service='Service1'; Propertyx=1; Price='7' }
)

Я хочу создать новый объект, чтобы сохранить идентификаторы, общие для всех трех. Итак, в этом примере результат должен включать только «1» и «2», поскольку они существуют во всех трех из них.

Я попытался почерпнуть некоторые идеи для адаптации из этого поста: Как получить «разницу» между двумя объектами в другом объекте с той же структурой с помощью PowerShell? но это не зашло далеко. Как я могу достичь этого эффективным образом.

В вашем примере так получилось, что другие свойства для Id абсолютно одинаковы как по имени, так и по своим значениям. Что произойдет, если это не так?

Theo 01.05.2024 16:43

@Theo: Спасибо, другие свойства - это просто я ленивый и копирую примеры data2 и data3 из того, что я набрал для данных 1 :) имена/значения этих свойств также могут быть разными, но они не входят в логику сопоставления, поэтому вы также можете представить, что это тоже разные имена и значения, но не в соответствующей логике.

Bohn 01.05.2024 16:48

Итак, насколько я понимаю, вам нужен результирующий объект только с общими идентификаторами, даже если эти свойства имеют разные имена и забывают о других свойствах? Можете ли вы привести пример желаемого результата?

Theo 01.05.2024 16:53

@Тео Спасибо, да, это правильно. Вы можете поместить их куда угодно, например, в список, в котором будут цифры 1 и 2. Так что позже я смогу использовать этот список для «фильтрации» этих трех источников данных и получения всей остальной информации на основе этих идентификаторов для каждого набора данных.

Bohn 01.05.2024 16:57

Для более эффективного способа вы можете использовать hahtable, см. Как в PowerShell лучше всего объединить две таблицы в одну? пост. Для простоты вы можете использовать предложенный JoinModule. Думаю, для этого вам нужно сделать следующее: $Data1 | Join $Data2 -on Id -eq AlsoId | Join $Data3 -on Id -eq IdToo | Select-Object Id

iRon 01.05.2024 18:14
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
5
58
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Один из вариантов — превратить любой список, кроме первого, в хеш-таблицу — тогда вы сможете перебирать первый список и быстро проверять, существует ли соответствующий объект в других списках:

# create a list of lists
$referenceLists = $data2,$data3

# iterate over the list of lists, collect output to `$indices`
$indices = for ($i = 0; $i -lt $referenceLists.Count; $i++) {
  $list = $referenceLists[$i]
  # define a hashtable to act as an index for the current list
  $index = @{}

  foreach ($item in $list) {
    # determine the appropriate property to correlate on 
    # order of property names matter here, `Id` preferred 
    $idPropertyName = 'Id','AlsoId','IdToo' |Where-Object { $item.psobject.Properties.Match($_) } |Select-Object -First 1

    $index[$item.$idPropertyName] = $item
  }

  # output populated index
  $index
}

Теперь у нас будет список хеш-таблиц, каждая из которых будет содержать все элементы из определенного списка, проиндексированные соответствующим идентификатором.

На этом этапе мы можем перебрать первый список и проверить корреляцию с каждым из только что заполненных индексов:

:outerLoop
foreach ($item in $data1) {
  foreach ($index in $indices) {
    if (-not $index.Contains($item.Id)) {
      # item not present in at least one other list -> skip
      continue outerLoop
    }

    # add additional comparison logic for further validation here
  }

  # if we reached this point it means the item was correlated (and perhaps validated) in all subsequent lists, output original item
  $item
}

Сланец :outerLoop перед внешним циклом foreach известен как метка потока управления, позволяющая нам сигнализировать о продолжении его выполнения, а не просто о продолжении внутреннего цикла.

Спасибо. Какое имя в -Expand Name в первом разделе кода? В нем говорится, что свойство «Имя» не найдено, а также ошибка в `$index[$item.$idPropertyName] = $item`, говорящая, что индекс массива имеет нулевое значение.

Bohn 01.05.2024 23:30

@Bohn Головоломка :-) Я удалил его сейчас

Mathias R. Jessen 01.05.2024 23:46

Спасибо, теперь я задал свой вопрос в ChatGPT, и он дал мне ответ. Я тоже публикую это здесь как ответ. Пожалуйста, посмотрите и выскажите свое мнение?

Bohn 01.05.2024 23:49

@Bohn Пожалуйста, не засоряйте сайт искусственным мусором :-) Кстати, сгенерированный ответ на самом деле не позволяет проводить дальнейшую проверку и/или проверку связанных объектов и станет непомерно медленным по мере увеличения размера входных данных.

Mathias R. Jessen 02.05.2024 00:43

Матиас, мне очень нравится использовать твой код, но он все равно вылетает $index[$item.$idPropertyName] = $item, говоря, что индекс массива имеет значение null. Вы запускали его с образцами данных? У меня это рушится.

Bohn 02.05.2024 14:06

@Bohn Возможно, вы попробовали это с объектом, который не имеет ни одного из перечисленных имен свойств в качестве членов?

Mathias R. Jessen 02.05.2024 14:25

Извиняюсь, да, возможно я сделал какую-то глупость. Это работает. Я буду использовать это. Спасибо. Кстати, у вас есть пример идеи, например, какой код я мог бы использовать в этой строке: # add additional comparison logic for further validation here чтобы я знал, как его использовать, если понадобится. Вы также можете придумать воображаемую ситуацию и пример кода.

Bohn 02.05.2024 18:04

@Bohn Это будет полностью зависеть от характера данных и вопросов, на которые вы пытаетесь ответить - например, представьте, что идентификатор не был глобально уникальным для разных сервисов, тогда вы можете выполнить вторичную проверку, например if ($index[$item.Id].Service -ne $item.Service) { continue outerLoop <# skip non-matching services #> }

Mathias R. Jessen 02.05.2024 18:10

Из ваших комментариев я понимаю, что вам нужен «Список идентификаторов, общих для всех трех массивов»

Это вернет массив, содержащий только значения идентификаторов, найденные во всех трех

$data1.id | Where-Object { $_ -in $data2.AlsoId -and $_ -in $data3.IdToo }

Это вернет массив, содержащий полные элементы $data1, значения идентификаторов которых были найдены во всех трех

$data1 | Where-Object { $_.id -in $data2.AlsoId -and $_.id -in $data3.IdToo }

да, поэтому следующим шагом будет получение данных (в отдельных переменных) из этих трех объектов data1, data2, data3, но отфильтрованных в «Список идентификаторов, общих для всех трех массивов»

Bohn 02.05.2024 15:14

Я не уверен, о чем вы спрашиваете. Не могли бы вы привести пример данных, которые вы хотите получить? Также: $data1, $data2, $data3 | ForEach-Object { $_ | ConvertTo-Csv -NoHeader } | ConvertFrom-Csv -Header Id, Service, Propertyx, Price | Select-Object -Property Id, Service, Propertyx, Price -Unique | Where-Object -Property Id -In $UniqueIdList | Group-Object -Property id -AsHashTable

sirtao 02.05.2024 15:58

Другие вопросы по теме