Как получить совпадения в ConcurrentQueue / Dictionary и сгруппировать их?
Имеется словарь, в котором записаны ключ и набор некоторых строковых данных.
IEnumerable<string> test1 = new List<string>()
{
"текст 1",
"текст 2",
"текст 3",
"текст 4",
"текст 5"
};
IEnumerable<string> test2 = new List<string>()
{
"текст 01",
"текст 02",
"текст 03",
"текст 3",
"текст 4",
"текст 5"
};
IEnumerable<string> test3 = new List<string>()
{
"текст 1",
"текст 2",
"текст 3",
"текст 49870",
"текст 687"
};
IEnumerable<string> test4 = new List<string>()
{
"текст 01",
"текст 02",
"текст 03",
"текст 411",
"текст 611"
};
ConcurrentQueue<Dictionary<string, IEnumerable<string>>> pairs = new ConcurrentQueue<Dictionary<string, IEnumerable<string>>>();
pairs.Enqueue(new Dictionary<string, IEnumerable<string>> { { "ключ 1", test1 }});
pairs.Enqueue(new Dictionary<string, IEnumerable<string>> { { "ключ 2", test2 } });
pairs.Enqueue(new Dictionary<string, IEnumerable<string>> { { "ключ 3", test3 } });
pairs.Enqueue(new Dictionary<string, IEnumerable<string>> { { "ключ 4", test4 } });
Как получить из pairs следующий результат:
Объединение №1 Объединены: 1, 3
Объединение №2 Объединены: 2, 4
Основное правило объединения это наличие в одном объединении только тех ключей, в которых имеются общие значения и минимальное количество таких общих значений равно 3.
То есть в urls1 и urls3 совпадает 2 значение: текст 1, текст 2, текст 3. В это объединение не входит urls2, так как у него есть общие значения только с urls1, но не с urls3.
Пробовал разные варианты, но так и не получилось что-то стоящее.
test1 = new List()
{
"текст 1",
"текст 2",
"текст 3",
"текст 4",
"текст 5"
};
test2 = new List()
{
"текст 01",
"текст 02",
"текст 03",
"текст 3",
"текст 4",
"текст 5"
};
test3 = new List()
{
"текст 1",
"текст 2",
"текст 3",
"текст 49870",
"текст 687"
};
test4 = new List()
{
"текст 01",
"текст 02",
"текст 03",
"текст 411",
"текст 611"
};
Если обходить с начала в конец, то берется test1 и считается что он маркерный и все остальное сравнить с ним и будет в результате набор объединений, внутри которых не обязательно все элементы содержат одинаковые наборы данных, т.е. минимум 3 совпадения по значениям.
Если так делать, то на первой итерации будет группа
test1 = new List()
{
"текст 1",
"текст 2",
"текст 3",
"текст 4",
"текст 5"
};
test2 = new List()
{
"текст 01",
"текст 02",
"текст 03",
"текст 3",
"текст 4",
"текст 5"
};
test3 = new List()
{
"текст 1",
"текст 2",
"текст 3",
"текст 49870",
"текст 687"
};
Так как test2 и test3 имеют что-то общее с test1. Теперь сравнение внутри группы и получается, что тут может быть 2 вариант
Лишний
test3 = new List()
{
"текст 1",
"текст 2",
"текст 3",
"текст 49870",
"текст 687"
};
Или лишний
test3 = new List()
{
"текст 1",
"текст 2",
"текст 3",
"текст 49870",
"текст 687"
};
Какой именно убрать помогает понять (тут не знаю точно как это сделать) последующие подобные рассуждения, когда становится видно, что удастся сформировать еще пару только в случае, когда лишний в первой группе будет
test2 = new List()
{
"текст 01",
"текст 02",
"текст 03",
"текст 3",
"текст 4",
"текст 5"
};
Так как его можно совместить с
test4 = new List()
{
"текст 01",
"текст 02",
"текст 03",
"текст 411",
"текст 611"
};
И не потерять объединение.
Итого получится
1 пара
test1 = new List()
{
"текст 1",
"текст 2",
"текст 3",
"текст 4",
"текст 5"
};
test3 = new List()
{
"текст 1",
"текст 2",
"текст 3",
"текст 49870",
"текст 687"
};
И вторая пара
test2 = new List()
{
"текст 01",
"текст 02",
"текст 03",
"текст 3",
"текст 4",
"текст 5"
};
test4 = new List()
{
"текст 01",
"текст 02",
"текст 03",
"текст 411",
"текст 611"
};
И вводных таких наборов данных в плане test может быть любое количество, четное или нечетное как угодно, но на выходе никаких дублей и прочего быть не должно, а что не удается объединить, то будет само по себе по типу объединение содержит 1 элемент ну и пусть.
Ответы (1 шт):
Если использование непосредственного ConcurrentQueue можно избежать, то попробуйте этот код:
var pairsAsArray = pairs.ToArray();
var unions = new List<Dictionary<string, IEnumerable<string>>[]>();
for (int i = 0; i < pairsAsArray.Length; i++)
{
for (int j = i + 1; j < pairsAsArray.Length; j++)
{
int matches = 0;
foreach (var value in pairsAsArray[j].Values.FirstOrDefault())
{
if (pairsAsArray[i].Values.FirstOrDefault().Contains(value))
{
matches++;
if (matches >= 3)
{
unions.Add(new Dictionary<string, IEnumerable<string>>[] { pairsAsArray[i], pairsAsArray[j] });
break;
}
}
}
}
}