Группировка значений
Подскажите, пожалуйста, есть таблица взаимозаменяемых запчастей, т.е. артикулы запчастей(колонка Article) могут иметь разное значение, но при этом быть взаимозаменяемыми. Они взаимозаменяемы, если у них одинаковое значение CrossGroupId. Например: Артикул A аналогичен артикулу B, т.к. CrossGroupId у обоих 1. Но в этой таблице есть потерянные связи.
A аналогичен B - GrossGroupId = 1
B аналогичен С - GrossGroupId = 2
B аналогичен D - GrossGroupId = 3
Здесь три группы, хотя A,B,C,D аналогичны друг другу и должны стоять в одной группе - GrossGroupId = 1.
начальная таблица
| Id | CrossGroupId | Article |
|---|---|---|
| 1 | 1 | A |
| 2 | 1 | B |
| 3 | 2 | B |
| 4 | 2 | C |
| 5 | 3 | B |
| 6 | 3 | D |
| 7 | 4 | E |
| 8 | 4 | F |
вот такая таблица должна получится
| Id | CrossGroupId | Article |
|---|---|---|
| 1 | 1 | A |
| 2 | 1 | B |
| 3 | 1 | C |
| 4 | 1 | D |
| 5 | 2 | E |
| 6 | 2 | F |
List<ArticleCross> articleCrosses = new() {
new ArticleCross { Id = 1, CrossGroupId = 1, Article = "A" },
new ArticleCross { Id = 1, CrossGroupId = 1, Article = "B" },
new ArticleCross { Id = 1, CrossGroupId = 2, Article = "B" },
new ArticleCross { Id = 1, CrossGroupId = 2, Article = "C" },
new ArticleCross { Id = 1, CrossGroupId = 3, Article = "B" },
new ArticleCross { Id = 1, CrossGroupId = 3, Article = "D",},
new ArticleCross { Id = 1, CrossGroupId = 4, Article = "E",},
new ArticleCross { Id = 1, CrossGroupId = 4, Article = "F",},
};
Думаю, что в цикле каждый раз делать группировку по Article пока не будет повторяющихся значений и менять CrossGroupId на Max из CrossGroupId в группе. Но кажется это сложно, буду признателен любой помощи.
Ответы (1 шт):
- Выбрать 1 группу
- Для каждого элемента выбрать группы, в которых он состоит
- Все найденные группы заменить на изначальную для всех элементов, которые в них есть, если таких замен нет, перейти к п.5
- Выбрать следующую группу, перейти к п.2, если следующей группы нет, то п.5
- Сделать Distinct() полученным результатам по Article
- Переименовать или перенумеровать группы при необходимости.
Попробовал Linq, но скорее всего это можно оптимизировать
class Program
{
static void Main(string[] args)
{
ArticleCross[] items = new[] {
new ArticleCross { CrossGroupId = 1, Article = "A" },
new ArticleCross { CrossGroupId = 1, Article = "B" },
new ArticleCross { CrossGroupId = 2, Article = "B" },
new ArticleCross { CrossGroupId = 2, Article = "C" },
new ArticleCross { CrossGroupId = 3, Article = "B" },
new ArticleCross { CrossGroupId = 3, Article = "D",},
new ArticleCross { CrossGroupId = 4, Article = "E",},
new ArticleCross { CrossGroupId = 4, Article = "F",},
};
foreach (int group in items.Select(x => x.CrossGroupId).Distinct().ToArray())
{
string[] names = items.Where(x => x.CrossGroupId == group).Select(x => x.Article).Distinct().ToArray();
ArticleCross[] cross = items.Where(x => x.CrossGroupId != group && names.Contains(x.Article)).ToArray();
int[] aliasGroups = cross.Select(x => x.CrossGroupId).Distinct().ToArray();
foreach (var item in items.Where(x => aliasGroups.Contains(x.CrossGroupId)))
{
item.CrossGroupId = group;
}
}
ArticleCross[] result = items.GroupBy(x => x.Article).Select(g => g.First()).ToArray();
foreach (var item in result)
{
Console.WriteLine($"{item.CrossGroupId} {item.Article}");
}
}
}
class ArticleCross
{
public int CrossGroupId { get; set; }
public string Article { get; set; }
}
Вывод в консоль
1 A
1 B
1 C
1 D
4 E
4 F