2016-03-06 2 views
2

У меня есть этот List<List<int>>:Как фильтровать список списка int с условием?

{{1,2},{1,3},{1,4},{2,3},{2,4},{3,4}} 

В этом списке есть 6 список, которые содержат цифры от 1 до 4, и возникновение каждого числа равно 3;

Я хочу, чтобы отфильтровать его, чтобы получить:

{{1,2}{1,3}{2,4}{3,4}} 

здесь возникновение каждого числа есть 2;

списки генерируются динамически, и я хочу, чтобы иметь возможность фильтровать также динамически, основываясь на событии;

Edit-Подробнее

Мне нужно подсчитать, сколько раз число содержит в List<List<int>>, для приведенного выше примера 3. Затем я хочу, чтобы исключить списки из List<List<int>> для того, чтобы уменьшить количество раз от 3 до 2, Основная проблема для меня заключалась в том, чтобы найти способ не блокировать мой компьютер :), а также чтобы каждый номер отображался в 2 раза (обязательно);

+2

Не могли бы вы добавить более подробную информацию о том, какие кортежи вы хотите опустить? Это не совсем понятно (для меня), чего вы пытаетесь достичь. –

+0

Звучит как-то прямо из [Project Euler] (https://projecteuler.net) :-) Мне это нравится! –

+0

@ RenéVogt Он хочет удалить те кортежи, которые при удалении приведут к тому, что все отдельные числа будут возникать определенное количество раз, например. 2 –

ответ

1

Ну, если это всегда сочетание 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) - так что если так случится, что очень первая (или вторая) комбинация успешна, она прекращает итерацию.

+0

Marty, listToTest.Add (данные [i]); -> здесь данные [i] - это список из моего примера? –

+0

Да, это исходные данные – Marty

0

Я принял ответ Марти, потому что исправил мою проблему, пытаясь использовать свой метод для больших списков, я обнаружил, что снова заблокировал свой компьютер, поэтому начинаю искать другой метод, и я заканчиваю его следующим:

var main = new List<HashSet<int>> { 
      new HashSet<int> {1,2}, 
      new HashSet<int> {1,3}, 
      new HashSet<int> {1,4}, 
      new HashSet<int> {2,3}, 
      new HashSet<int> {2,4}, 
      new HashSet<int> {3,4} }; 


     var items = new HashSet<int>(from l in main from p in l select p); //=>{1,2,3,4} 


     for (int i =main.Count-1;i-->0;) 
     {    
      var occurence=items.Select(a=> main.Where(x => x.Contains(a)).Count()).ToList(); 
      var occurenceSum = 0; 
      foreach(var j in main[i]) 
      { 
       occurenceSum += occurence[j - 1]; 
       if (occurenceSum==6) //if both items have occurence=3, then the sum=6, then I can remove that list! 
       { 
        main.RemoveAt(i); 

       } 
      }    

     } 
Смежные вопросы