комбинации c # с linq - PullRequest
       0

комбинации c # с linq

1 голос
/ 23 марта 2011

У меня есть массив значений, например {0, 1, 2}, который может находиться в одном из двух состояний {0, 1}.

Есть ли простой способ (возможно, с использованием запроса linq), чтобы получить список всех комбинаций {value, state} (где значение уникально), чтобы я мог получить такие результаты, как:

{
{ { 0, 0 }, { 1, 0 }, { 2, 0 } },
{ { 0, 0 }, { 1, 0 }, { 2, 1 } },
{ { 0, 0 }, { 1, 1 }, { 2, 0 } },
{ { 0, 0 }, { 1, 1 }, { 2, 1 } },
{ { 0, 1 }, { 1, 0 }, { 2, 0 } },
{ { 0, 1 }, { 1, 0 }, { 2, 1 } },
{ { 0, 1 }, { 1, 1 }, { 2, 0 } },
{ { 0, 1 }, { 1, 1 }, { 2, 1 } },
}

Массив "value" может иметь различный размер, но он может быть только в одном из двух состояний.

(Это не декартово произведение, и я не уверен, какой термин можно использовать для его описания, поэтому не знаю, что гуглить).

Спасибо!

Ответы [ 4 ]

3 голосов
/ 23 марта 2011

Это декартово произведение декартовых произведений:

var groups = from x in 
                (from v in values
                 from s in states
                 select new {v,s})
             group x by x.v into gx
             select gx;

var perms = from a in groups[0]
            from b in groups[1]
            from c in groups[2]
            select new {a,b,c}; 

Запрос групп создает Lookup (концептуально только для чтения словарь IEnumerables), содержащий простое декартово произведение всех значений и состояний (6 элементов)сгруппированы по их стоимости.Затем второй запрос создает декартово произведение элементов декартового произведения, взятых по три за раз, по одному от каждой группы в Lookup.

Сделать эту работу с неизвестным количеством измерений было бы сложно;если бы вам не приходилось делать так, я бы этого не делал.Я думаю, что наиболее элегантный способ - это определить набор методов расширения для универсальных классов System.Tuple:

public static Tuple<T1,T2> Append(this Tuple<T1> tuple, T2 addend)
{
   return Tuple.Create(tuple.Item1, addend);
}

public static Tuple<T1,T2, T3> Append(this Tuple<T1,T2> tuple, T3 addend)
{
   return Tuple.Create(tuple.Item1, tuple.Item2, addend);
}

...

Затем вы можете взять эти помощники и использовать их в зацикленной версии второго запроса.:

var perms = из a в группах [0] выберите Tuple.Create (a);

foreach (var group в groups.Skip (1)) perms = из a в perms изb в группе выберите a.Append (b);

Это создаст перечисляемый набор кортежей необходимой длины, содержащий элементы анонимного типа, созданные в первом запросе (которые могут быть реорганизованы для получения сильнонабрал 2-элементный кортеж, если хотите).У вас могут возникнуть проблемы с использованием переменной perms collection для ссылки на коллекции постоянно растущих кортежей;это сложная часть.

2 голосов
/ 23 марта 2011

попробуй

var values = new int[]{0,1,2};
var states = new int[]{0,1};

var permutations = from v in values
                   from s in states
                   select new {v,s}

вам просто нужно перекрестное произведение двух массивов независимо от размера массивов

0 голосов
/ 23 марта 2011

Поскольку два состояния можно рассматривать как биты, вы можете получить комбинации, просто посчитав и преобразовав биты в элементы в массиве:

int maxValue = 2;
int[][][] values = Enumerable.Range(0, 1 << maxValue).Select(n =>
  Enumerable.Range(0, maxValue + 1).Select(m =>
    new[] { m, (n >> (maxValue - m)) & 1 }
  ).ToArray()
).ToArray();
0 голосов
/ 23 марта 2011

Может быть что-то вроде:

var lst1 = new List<int> { 0, 1, 2 };
var lst2 = new List<int> { 0, 1 };

lst1.ForEach(i => {
    Console.WriteLine("{");
    lst2.ForEach(j => Console.Write("{ " + i + "," + j + "}"));
    Console.WriteLine("}");
});

Это не будет в том формате, который вы хотите; Вы должны создать какой-нибудь массив (ы) и затем присоединить его к "," и / или "}, {". Это должно дать вам общее представление.

...