Ну, если это всегда сочетание 2-х номеров, и они должны появляться N раз в списке, это означает, что в зависимости от N вы собираетесь иметь:
4 (разные цифры) х 2 (раза эй должны появляться) = 8 цифр = 4 пары
4 х 3 (раз) = 12 = 6 (пар)
4 х 4 = 16 = 8 пар
Это означает - что с 6 пар мы знаем, что мы должны выбрать 4 пары, которые наилучшим образом соответствуют критериям
поэтому на основе базовой комбинаторики (https://www.khanacademy.org/math/probability/probability-and-combinatorics-topic/permutations/v/permutation-formula) у нас есть 6!/2! = (6 * 5 * 4 * 3 * 2 * 1)/(2 * 1) = 360 возможных перестановок
В принципе у вас может быть 360 различных способов, как вы совмещаете второй список.
, потому что это не имеет значения, как вы расположите элементы в списке (порядок элементов в списке), то число возможных комбинаций 6!/(2! * 4!) = 15 https://www.khanacademy.org/math/probability/probability-and-combinatorics-topic/combinations-combinatorics/v/combination-formula
так что дело - у вас есть 15 возможных ответов на ваш вопрос. Это означает, что вам нужно всего лишь обходить его 15 раз. Есть только 15 способов выбрать 4 объекта из списка 6
похоже, что это решение для вас - вопрос «убить машину».
так следующий вопрос - как мы находим всю возможную «комбинацию» Давайте определим все возможные элементы, которые мы можем выбрать из входного массива , например, 1-й, 2-й, 3-й и 4- th ..
1,2,3,4 ....... 1,2,3,5 ...... 1,2,3,6 ...
Все комбинации были бы (отсюда https://stackoverflow.com/a/10629938/444149)
static IEnumerable<IEnumerable<T>> GetKCombs<T>(IEnumerable<T> list, int length) where T : IComparable
{
if (length == 1) return list.Select(t => new T[] { t });
return GetKCombs(list, length - 1)
.SelectMany(t => list.Where(o => o.CompareTo(t.Last()) > 0),
(t1, t2) => t1.Concat(new T[] { t2 }));
}
и вызывать с (потому что есть 6 пунктов, чтобы выбрать из, кто индексированные являются 0,1,2,3,4 и 5)
var possiblePicks = GetKCombs(new List<int> { 0, 1, 2, 3, 4, 5 }, 4);
мы получаем 15 возможных комбинаций , так что теперь - мы стараемся принимать 4 элемента из первого списка, и проверить, если они соответствуют критериям .. если нет .. то взять другую комбинацию
var data = new List<List<int>>
{
new List<int> { 1,2 },
new List<int> { 1,3 },
new List<int> { 1,4 },
new List<int> { 2,3 },
new List<int> { 2,4 },
new List<int> { 3,4 }
};
foreach (var picks in possiblePicks)
{
var listToTest = new List<List<int>>(4);
foreach (var i in picks)
listToTest.Add(data[i]);
var ok = Check(listToTest, 2);
if (ok)
break;
}
private bool Check(List<List<int>> listToTest, int limit)
{
Dictionary<int, int> ret = new Dictionary<int, int>();
foreach (var inputElem in listToTest)
{
foreach (var z in inputElem)
{
var returnCount = ret.ContainsKey(z) ? ret[z] : 0;
if (!ret.ContainsKey(z))
ret.Add(z, returnCount + 1);
else
ret[z]++;
}
}
return ret.All(p => p.Value == limit);
}
Я уверен, что это может быть оптимизировано, чтобы минимизировать количество других итераций «listToTest»
Кроме того, это ленивая реализация (IEnumerable) - так что если так случится, что очень первая (или вторая) комбинация успешна, она прекращает итерацию.
Не могли бы вы добавить более подробную информацию о том, какие кортежи вы хотите опустить? Это не совсем понятно (для меня), чего вы пытаетесь достичь. –
Звучит как-то прямо из [Project Euler] (https://projecteuler.net) :-) Мне это нравится! –
@ RenéVogt Он хочет удалить те кортежи, которые при удалении приведут к тому, что все отдельные числа будут возникать определенное количество раз, например. 2 –