Перейти к содержимому

Как объединить две коллекции c

  • автор:

Операции над множествами (C#)

Операции над множествами в LINQ — это операции запросов, результирующие наборы которых основываются на наличии или отсутствии эквивалентных элементов в одной или другой коллекции (или наборе).

Методы стандартных операторов запросов, которые выполняют операции над множествами, перечислены в следующем разделе.

Методы

Имена методов Описание Синтаксис выражения запроса C# Дополнительные сведения
Distinct или DistinctBy Удаляет повторяющиеся значения из коллекции. Не применяется Enumerable.Distinct
Enumerable.DistinctBy
Queryable.Distinct
Queryable.DistinctBy
Except или ExceptBy Возвращает разность множеств, т. е. элементы одной коллекции, которые отсутствуют во второй. Не применяется Enumerable.Except
Enumerable.ExceptBy
Queryable.Except
Queryable.ExceptBy
Intersect или IntersectBy Возвращает пересечение множеств, т. е. элементы, присутствующие в каждой из двух коллекций. Не применяется Enumerable.Intersect
Enumerable.IntersectBy
Queryable.Intersect
Queryable.IntersectBy
Union или UnionBy Возвращает объединение множеств, т. е. уникальные элементы, присутствующие в одной из двух коллекций. Не применяется Enumerable.Union
Enumerable.UnionBy
Queryable.Union
Queryable.UnionBy

Примеры

В некоторых из приведенных ниже примеров используется тип record , который представляет планеты Солнечной системы.

namespace SolarSystem; record Planet( string Name, PlanetType Type, int OrderFromSun) < public static readonly Planet Mercury = new(nameof(Mercury), PlanetType.Rock, 1); public static readonly Planet Venus = new(nameof(Venus), PlanetType.Rock, 2); public static readonly Planet Earth = new(nameof(Earth), PlanetType.Rock, 3); public static readonly Planet Mars = new(nameof(Mars), PlanetType.Rock, 4); public static readonly Planet Jupiter = new(nameof(Jupiter), PlanetType.Gas, 5); public static readonly Planet Saturn = new(nameof(Saturn), PlanetType.Gas, 6); public static readonly Planet Uranus = new(nameof(Uranus), PlanetType.Liquid, 7); public static readonly Planet Neptune = new(nameof(Neptune), PlanetType.Liquid, 8); // Yes, I know. not technically a planet anymore public static readonly Planet Pluto = new(nameof(Pluto), PlanetType.Ice, 9); >

Для создания экземпляра позиционной записи record Planet требуются аргументы Name , Type и OrderFromSun . Существует несколько экземпляров планет static readonly типа Planet . Это удобные определения для хорошо известных планет. Элемент Type определяет тип планеты.

namespace SolarSystem; enum PlanetType < Rock, Ice, Gas, Liquid >; 

Distinct и DistinctBy

В следующем примере показано поведение метода Enumerable.Distinct применительно к последовательности строк. Возвращаемая последовательность содержит уникальные элементы из входной последовательности.

График, демонстрирующий поведение Distinct().

string[] planets = ["Mercury", "Venus", "Venus", "Earth", "Mars", "Earth"]; IEnumerable query = from planet in planets.Distinct() select planet; foreach (var str in query) < Console.WriteLine(str); >/* This code produces the following output: * * Mercury * Venus * Earth * Mars */ 

Вместо Distinct можно использовать DistinctBy , который принимает keySelector . keySelector используется как сравнительный дискриминатор для типа источника. Давайте рассмотрим следующий массив планет:

Planet[] planets = [ Planet.Mercury, Planet.Venus, Planet.Earth, Planet.Mars, Planet.Jupiter, Planet.Saturn, Planet.Uranus, Planet.Neptune, Planet.Pluto ]; 

В следующем коде планеты разделяются на основе PlanetType . При этом отображается первая планета каждого типа:

foreach (Planet planet in planets.DistinctBy(p => p.Type)) < Console.WriteLine(planet); >// This code produces the following output: // Planet < Name = Mercury, Type = Rock, OrderFromSun = 1 >// Planet < Name = Jupiter, Type = Gas, OrderFromSun = 5 >// Planet < Name = Uranus, Type = Liquid, OrderFromSun = 7 >// Planet

В приведенном выше коде C#:

  • Массив Planet фильтруется по первому вхождению каждого уникального типа планеты.
  • Полученные экземпляры planet записываются в консоль.

Except и ExceptBy

В следующем примере показано поведение Enumerable.Except. Возвращаемая последовательность содержит только те элементы из первой входной последовательности, которых нет во второй.

Рисунок, показывающий действие Except().

string[] planets1 = ["Mercury", "Venus", "Earth", "Jupiter"]; string[] planets2 = ["Mercury", "Earth", "Mars", "Jupiter"]; IEnumerable query = from planet in planets1.Except(planets2) select planet; foreach (var str in query) < Console.WriteLine(str); >/* This code produces the following output: * * Venus */ 

Вместо Except можно использовать метод ExceptBy, который принимает две последовательности потенциально разнородных типов и keySelector . Тип keySelector совпадает с типом второй коллекции и используется как сравнительный дискриминатор для типа источника. Давайте рассмотрим следующий массив планет:

Planet[] planets = [ Planet.Mercury, Planet.Venus, Planet.Earth, Planet.Jupiter ]; Planet[] morePlanets = [ Planet.Mercury, Planet.Earth, Planet.Mars, Planet.Jupiter ]; 

Чтобы найти планеты из первой коллекции, которые не входят во вторую коллекцию, можно проецировать имена планет в виде коллекции second с прежним значением keySelector :

// A shared "keySelector" static string PlanetNameSelector(Planet planet) => planet.Name; foreach (Planet planet in planets.ExceptBy( morePlanets.Select(PlanetNameSelector), PlanetNameSelector)) < Console.WriteLine(planet); >// This code produces the following output: // Planet

В приведенном выше коде C#:

  • keySelector определяется как локальная функция static , которая различает имена планет.
  • Первый массив планет фильтруется, чтобы получить отсутствующие во втором массиве планеты, на основе имен планет.
  • Полученный экземпляр planet записывается в консоль.

Intersect и IntersectBy

В следующем примере показано поведение Enumerable.Intersect. Возвращаемая последовательность содержит элементы, общие для обеих входных последовательностей.

График, отображающий пересечение двух последовательностей.

string[] planets1 = ["Mercury", "Venus", "Earth", "Jupiter"]; string[] planets2 = ["Mercury", "Earth", "Mars", "Jupiter"]; IEnumerable query = from planet in planets1.Intersect(planets2) select planet; foreach (var str in query) < Console.WriteLine(str); >/* This code produces the following output: * * Mercury * Earth * Jupiter */ 

Вместо Intersect можно использовать метод IntersectBy, который принимает две последовательности потенциально разнородных типов и keySelector . keySelector используется как сравнительный дискриминатор для типа второй коллекции. Давайте рассмотрим следующий массив планет:

Planet[] firstFivePlanetsFromTheSun = [ Planet.Mercury, Planet.Venus, Planet.Earth, Planet.Mars, Planet.Jupiter ]; Planet[] lastFivePlanetsFromTheSun = [ Planet.Mars, Planet.Jupiter, Planet.Saturn, Planet.Uranus, Planet.Neptune ]; 

Существует два массива планет, один из которых представляет первые пять планет от Солнца, а второй — последние пять планет. Так как тип Planet является позиционным типом record , вы можете использовать его семантику сравнения значений в формате keySelector :

foreach (Planet planet in firstFivePlanetsFromTheSun.IntersectBy( lastFivePlanetsFromTheSun, planet => planet)) < Console.WriteLine(planet); >// This code produces the following output: // Planet < Name = Mars, Type = Rock, OrderFromSun = 4 >// Planet

В приведенном выше коде C#:

  • Два массива Planet пересекаются с использованием семантики сравнения их значений.
  • В результирующей последовательности содержатся только те планеты, которые обнаружены в обоих массивах.
  • Полученные экземпляры planet записываются в консоль.

Union и UnionBy

В следующем примере показана операция объединения двух последовательностей строк. Возвращаемая последовательность содержит уникальные элементы из обеих входных последовательностей.

График, показывающий объединение двух последовательностей.

string[] planets1 = ["Mercury", "Venus", "Earth", "Jupiter"]; string[] planets2 = ["Mercury", "Earth", "Mars", "Jupiter"]; IEnumerable query = from planet in planets1.Union(planets2) select planet; foreach (var str in query) < Console.WriteLine(str); >/* This code produces the following output: * * Mercury * Venus * Earth * Jupiter * Mars */ 

Вместо Union можно использовать метод UnionBy, который принимает две последовательности одного типа и keySelector . keySelector используется как сравнительный дискриминатор для типа источника. Давайте рассмотрим следующий массив планет:

Planet[] firstFivePlanetsFromTheSun = [ Planet.Mercury, Planet.Venus, Planet.Earth, Planet.Mars, Planet.Jupiter ]; Planet[] lastFivePlanetsFromTheSun = [ Planet.Mars, Planet.Jupiter, Planet.Saturn, Planet.Uranus, Planet.Neptune ]; 

Чтобы объединить эти две коллекции в одну последовательность, укажите keySelector :

foreach (Planet planet in firstFivePlanetsFromTheSun.UnionBy( lastFivePlanetsFromTheSun, planet => planet)) < Console.WriteLine(planet); >// This code produces the following output: // Planet < Name = Mercury, Type = Rock, OrderFromSun = 1 >// Planet < Name = Venus, Type = Rock, OrderFromSun = 2 >// Planet < Name = Earth, Type = Rock, OrderFromSun = 3 >// Planet < Name = Mars, Type = Rock, OrderFromSun = 4 >// Planet < Name = Jupiter, Type = Gas, OrderFromSun = 5 >// Planet < Name = Saturn, Type = Gas, OrderFromSun = 6 >// Planet < Name = Uranus, Type = Liquid, OrderFromSun = 7 >// Planet

В приведенном выше коде C#:

  • Эти два массива Planet объединяются с использованием семантики сравнения значений record .
  • Полученные экземпляры planet записываются в консоль.

См. также

  • System.Linq
  • Общие сведения о стандартных операторах запроса (C#)
  • Практическое руководство. Объединение и сравнение коллекций строк (LINQ) (C#)
  • Нахождение разности множеств между двумя списками (LINQ) (C#)

Совместная работа с нами на GitHub

Источник этого содержимого можно найти на GitHub, где также можно создавать и просматривать проблемы и запросы на вытягивание. Дополнительные сведения см. в нашем руководстве для участников.

Объединение двух коллекций Laravel

У меня болит голова от работы с коллекциями Laravel. У меня две коллекции:

 $dt = Carbon::now(); $days = new Collection([]); /** * Create a calender month */ for ($day = 1; $day daysInMonth; $day++) < $date = Carbon::create($dt->year, $dt->month, $day)->toDateString(); $days->push(new Timesheet([ 'date' => $date, ])); > /** * Get all timesheets for user */ $timesheets = Timesheet::where('user_id', $this->user->id) ->get(); 
#attributes: array:5 [▼ "id" => "1" "user_id" => "1" "date" => "2016-02-22 22:05:01" "created_at" => "2016-02-22 22:05:01" "updated_at" => "2016-02-22 22:05:01" ] // . one or more . 

У меня есть вторая коллекция, дающая мне все дни в течение определенного месяца.

#attributes: array:1 [▼ "date" => "2016-02-01 00:00:00" ] // . and the rest of the month. 

Я хочу объединить коллекцию $days с коллекцией $timesheet , сохраняя значения коллекции $timesheet и удаляя любые дубликаты, присутствующие в коллекции $days . E. g. если $timesheets уже содержит ‘2016-02-24’ я не, нужно объединить ‘2016-02-24’ с $days . Как это сделать?

Источник

  • 314
  • 4
  • 2020-12-26 10:25:39
  • BusterX
Требуется авторизация

Вы должны войти, чтобы оставить комментарий.

  • Avatar
Don’t Panic — 2 года назад

Я думаю, что одним из способов сделать это было бы добавить метод к вашей модели Movie , используя hasManyThrough , чтобы получить другие фильмы, связанные с режиссером.

public function relatedMovies() < return $this->hasManyThrough('App\Movie', 'App\Director'); > 

Затем отдельно загружать эту связь, а не загружать вложенные отношения.

$movie = Movie::with('directors', 'relatedMovies')->find(1); 

Ответить 0

Avatar

Mike Miller — 2 года назад

Хорошо, продолжайте с этим. Логика должна в значительной степени работать, но obv не имеет доступа к вашему классу расписания.

$days = new Collection([]); //basically the same structure i think $timesheets = new Collection([new Collection(['date'=>'2016-02-23','created_at'=>'2016-02-23 14:12:34']),new Collection(['date'=>'2016-02-28','created_at'=>'2016-02-23 14:15:36'])]); $dt = Carbon::now(); for ($day = 1; $day daysInMonth; $day++) < $date = Carbon::create($dt->year, $dt->month, $day)->format('Y-m-d'); //filter your timesheets and see if there is one for this day $timesheet = $timesheets->filter(function($timesheet) use($date)get('date')==$date;>); if(!$timesheet->isEmpty())< //if there is a timesheet for today then add it to your $days collection $days->push($timesheet); >else< //otherwise just stick in the date $days->push(new Collection([ 'date' => $date, ])); > > //voila! dd($days); 

Ответить 0

Avatar

Jeff Lambert — 2 года назад

Используйте merge :

$collection1 = Model1::all(); $collection2 = Model2::all(); $mergedCollection = $collection1->merge($collection2); 

Документация В документации говорится об использовании ее с массивами, но, глядя на подпись метода, она будет принимать смешанные аргументы. Тестирование его на локальную установку проекта Laravel 4 сработало для меня.

Ответить 0

Avatar

Dwijen — 2 года назад

Я не уверен, почему $merged = $timesheets->merge($days); слил только последний элемент. Может быть, кто-то еще может пролить свет на него. Но пока не будет лучшего решения, вы можете это сделать — $merged = array_merge($timesheets->toArray(), $days->toArray()); Надеюсь, что это поможет.

Ответить 0

Как объединить две коллекции c

LINQ предоставляет несколько методов для работы с коллекциями как с множествами, а именно находить их разность, объединение и пересечение.

Разность последовательностей

С помощью метода Except() можно получить разность двух последовательностей:

string[] soft = < "Microsoft", "Google", "Apple">; string[] hard = < "Apple", "IBM", "Samsung">; // разность последовательностей var result = soft.Except(hard); foreach (string s in result) Console.WriteLine(s);

В данном случае из массива soft убираются все элементы, которые есть в массиве hard . Результатом операции будут два элемента:

Microsoft Google

Пересечение последовательностей

Для получения пересечения последовательностей, то есть общих для обоих наборов элементов, применяется метод Intersect :

string[] soft = < "Microsoft", "Google", "Apple">; string[] hard = < "Apple", "IBM", "Samsung">; // пересечение последовательностей var result = soft.Intersect(hard); foreach (string s in result) Console.WriteLine(s);

Так как оба набора имеют только один общий элемент, то соответственно только он и попадет в результирующую выборку:

Apple

Удаление дубликатов

Для удаления дублей в наборе используется метод Distinct :

string[] soft = < "Microsoft", "Google", "Apple", "Microsoft", "Google" >; // удаление дублей var result = soft.Distinct(); foreach (string s in result) Console.WriteLine(s);
Microsoft Google Apple

Объединение последовательностей

Для объединения двух последовательностей используется метод Union . Его результатом является новый набор, в котором имеются элементы, как из первой, так и из второй последовательности. Повторяющиеся элементы добавляются в результат только один раз:

string[] soft = < "Microsoft", "Google", "Apple">; string[] hard = < "Apple", "IBM", "Samsung">; // объединение последовательностей var result = soft.Union(hard); foreach (string s in result) Console.WriteLine(s);

Результатом операции будет следующий набор:

Microsoft Google Apple IBM Samsung

Если же нам нужно простое объединение двух наборов, то мы можем использовать метод Concat :

var result = soft.Concat(hard);

В этом случае те элементы, которые встречаются в обоих наборах, дублируются в резутирующей последовательности.

Последовательное применение методов Concat и Distinct будет подобно действию метода Union.

Работа со сложными объектами

Для сравнения объектов в последовательностях применяются реализации методов GetHeshCode() и Equals(). Поэтому если мы хотим работать с последовательностями, которые содержат объекты своих классов и структур, то нам необходимо определить для них подобные методы:

Person[] students = < new Person("Tom"), new Person("Bob"), new Person("Sam") >; Person[] employees = < new Person("Tom"), new Person("Bob"), new Person("Mike") >; // объединение последовательностей var people = students.Union(employees); foreach (Person person in people) Console.WriteLine(person.Name); class Person < public string Name < get;>public Person(string name) => Name = name; public override bool Equals(object? obj) < if (obj is Person person) return Name == person.Name; return false; >public override int GetHashCode() => Name.GetHashCode(); >

Здесь объекты Person сравниваются исходя из значения их свойства Name — если имена равны, то и объекты Person равны. Консольный вывод:

Как объединить не сколько коллекций в одну?

Приветствую всех! Сегодня хочу показать пример как с помощь LINQ, объединить коллекцию в одну. По условию задания у нас дана коллекция, главный метод и метод который мы должны дописать:

public class Classroom
public List < string >Students = new List < string >( ) ;
public static void Main ( )
Classroom [ ] classes =
new Classroom < Students = < "Pavel" , "Ivan" , "Petr" >, > ,
new Classroom < Students = < "Anna" , "Ilya" , "Vladimir" >, > ,
new Classroom < Students = < "Bulat" , "Alex" , "Galina" >, >
var allStudents = GetAllStudents ( classes ) ;
Array . Sort ( allStudents ) ;
Console . WriteLine ( string . Join ( » » , allStudents ) ) ;
public static string [ ] GetAllStudents ( Classroom [ ] classes )

Как видно в метод GetAllStudents принимает коллекцию коллекций. А вернуть нам нужно массив string[] Который содержит имена всех студентов.

Решение этой тривиальной задачи будет в одну строчку кода, которую мы решим с помощью Linq:

public static string [ ] GetAllStudents ( Classroom [ ] classes )
return classes . SelectMany ( s = > s . Students ) . ToArray ( ) ;

Для решения этой задачи воспользуемся методом SelectMany, почитать можете в чем разница между Select и SelectMany тут всю коллекцию преобразуем в массив string() с помощью метода ToArray();

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *