[英]Using LINQ get all possible pair of connections from two lists
Given lists Input = {A, B} and Output = {1, 2, 3, 4 }, I want to get a new list that contains all possible pair of connections {connection1,connection2} : 给定列表Input = {A,B}和Output = {1,2,3,4},我想得到一个包含所有可能的连接对{connection1,connection2}的新列表:
connections = {A1, B2},
{A1, B3},
{A1, B4},
{A2, B1},
{A2, B3},
{A2, B4},
{A3, B1},
{A3, B2},
{A3, B4},
{A4, B1},
{A4, B2},
{A4, B3}
Rules : 规则 :
Illustration of connection {A1, B3} 连接图示{A1,B3}
Suggestions? 建议?
Updated Answer 更新的答案
This should do it: 这应该这样做:
using System.Linq;
using static System.Console;
class Program {
static void Main(string[] args) {
var inputs = new[] { "A", "B", "C" };
var outputs = new[] { "1", "2", "3", "4" };
var res = from i1 in inputs
from i2 in inputs
where i1 != i2
from o1 in outputs
from o2 in outputs
where o1 != o2
let c1 = i1 + o1
let c2 = i2 + o2
// Avoid {x,y} and {y,x} in result.
where c1.CompareTo(c2) < 0
select (first: c1, second: c2);
foreach (var r in res) {
WriteLine($"{{{r.first}, {r.second}}}");
}
}
}
Original Answer 原始答案
You need the LINQ to Objects equivalent of a cross join, which is just looping over the contents of both lists without any conditions to limit the set of results. 您需要相当于交叉连接的LINQ to Objects,它只是循环遍历两个列表的内容,而没有任何限制结果集的条件。
var allPairs = (from a in ListA
from b in ListB
select (a, b)
).ToList();
Will give you a list of all pairs as tuples. 将为您提供所有对的列表作为元组。
In your case you seem to want all pairs of pairs: given all combinations of input and output then get all pairs of combinations on input and output. 在你的情况下,你似乎想要所有成对的对:给定输入和输出的所有组合,然后获得输入和输出的所有组合。
Which is just a case of expanding the above with a second combination of the list of all input-output combinations. 这只是通过所有输入 - 输出组合列表的第二组合来扩展上述情况的情况。
// Assume `Input` and `Output` and enumerables of string
var inputOutputPairs = (from ip in Input
from op in Output
select ip + op
).ToList();
var result = (from left in inputOutputPairs
from right in inputOutputPairs
select (left, right)
// To avoid duplicates like ("A4","A4") include this:
// where left != right
).ToList();
And the result will be a list of ValueTuple<string, string>
. 结果将是ValueTuple<string, string>
。
Richard's updated answer is elegant and probably the best fit for your needs, but I suggest an alternative idea using combinatorics. 理查德的最新答案很优雅,可能最适合您的需求,但我建议使用组合学的另一种想法。 (and also using function-style linq which is imho a lot easier to debug and maintain). (还使用函数式linq,它更易于调试和维护)。
The idea is: 这个想法是:
Example implementation using a pre-baked combinatorics package from NuGet : 使用NuGet的预烘焙组合包的示例实现:
var Input = new[] { "A", "B"};
var Output = new[] { "1", "2", "3", "4" };
int maxConnections = 2;
var validInputs = new Combinations<String>(Input, maxConnections);
var validOutputs = new Variations<String>(Output, maxConnections);
var connectionsets = validInputs
.SelectMany(ins => validOutputs
.Select(outs => new { Ins = ins, Outs = outs })
);
To get the connection from the format of ins/outs to single string, you could use something along the lines of : 要获得从ins / out格式到单个字符串的连接,您可以使用以下内容:
String.Join(",", set.Ins.Select((input, i) => input + set.Outs.Skip(i).First()));
NB! NB! Also note that this approach enables you to solve a bit wider question of finding N connections instead of just 2. 另请注意,此方法使您能够解决更广泛的问题,即找到N个连接,而不仅仅是2个。
I've written an unit test with the example you provide and a working implementation: 我用你提供的例子和一个有效的实现编写了一个单元测试:
public static class PairsOfConnections
{
public static IEnumerable<Tuple<string, string>> GetAllPairsOfConnections(string[] input, string[] output)
{
var connectionsFromFirstInput = output.Select(o => new { Input = input[0], Output = o });
var connectionsFromSecondInput = output.Select(o => new { Input = input[1], Output = o }).ToList();
return from a in connectionsFromFirstInput
from b in connectionsFromSecondInput
where a.Output != b.Output
select new Tuple<string, string>(a.Input + a.Output, b.Input + b.Output);
}
}
public class PairsOfConnectionsTests
{
[Test]
public void TestGetAllPairsOfConnections()
{
string[] input = { "A", "B" };
string[] output = { "1", "2", "3", "4" };
IEnumerable<Tuple<string, string>> result = PairsOfConnections.GetAllPairsOfConnections(input, output);
var expected = new List<Tuple<string, string>>
{
new Tuple<string, string>("A1","B2"),
new Tuple<string, string>("A1","B3"),
new Tuple<string, string>("A1","B4"),
new Tuple<string, string>("A2","B1"),
new Tuple<string, string>("A2","B3"),
new Tuple<string, string>("A2","B4"),
new Tuple<string, string>("A3","B1"),
new Tuple<string, string>("A3","B2"),
new Tuple<string, string>("A3","B4"),
new Tuple<string, string>("A4","B1"),
new Tuple<string, string>("A4","B2"),
new Tuple<string, string>("A4","B3")
};
CollectionAssert.AreEquivalent(expected, result);
}
}
Seeing that you have clarified that there can be more than two inputs, I've written a modified algorithm, with the same unit test as before, and a new one: 看到你已经澄清了可以有两个以上的输入,我编写了一个修改过的算法,使用与以前相同的单元测试,并且新的算法:
public static class PairsOfConnections
{
public static IEnumerable<Tuple<string, string>> GetAllPairsOfConnections(string[] inputs, string[] outputs)
{
var connectionsFromFirstInput = outputs.Select(o => new { Input = inputs[0], Output = o }).ToList();
var result = new List<Tuple<string, string>>();
foreach (string input in inputs.Skip(1))
{
var connectionsFromNextInput = outputs.Select(output => new { Input = input, Output = output }).ToList();
IEnumerable<Tuple<string, string>> pairs = from a in connectionsFromFirstInput
from b in connectionsFromNextInput
where a.Output != b.Output
select new Tuple<string, string>(a.Input + a.Output, b.Input + b.Output);
result.AddRange(pairs);
}
return result;
}
}
public class PairsOfConnectionsTests
{
[Test]
public void TestGetAllPairsOfConnections_WithTwoInputs()
{
string[] input = { "A", "B" };
string[] output = { "1", "2", "3", "4" };
IEnumerable<Tuple<string, string>> result = PairsOfConnections.GetAllPairsOfConnections(input, output);
var expected = new List<Tuple<string, string>>
{
new Tuple<string, string>("A1","B2"),
new Tuple<string, string>("A1","B3"),
new Tuple<string, string>("A1","B4"),
new Tuple<string, string>("A2","B1"),
new Tuple<string, string>("A2","B3"),
new Tuple<string, string>("A2","B4"),
new Tuple<string, string>("A3","B1"),
new Tuple<string, string>("A3","B2"),
new Tuple<string, string>("A3","B4"),
new Tuple<string, string>("A4","B1"),
new Tuple<string, string>("A4","B2"),
new Tuple<string, string>("A4","B3")
};
CollectionAssert.AreEquivalent(expected, result);
}
[Test]
public void TestGetAllPairsOfConnections_WithThreeInputs()
{
string[] input = { "A", "B", "C" };
string[] output = { "1", "2", "3" };
IEnumerable<Tuple<string, string>> result = PairsOfConnections.GetAllPairsOfConnections(input, output);
var expected = new List<Tuple<string, string>>
{
new Tuple<string, string>("A1","B2"),
new Tuple<string, string>("A1","B3"),
new Tuple<string, string>("A1","C2"),
new Tuple<string, string>("A1","C3"),
new Tuple<string, string>("A2","B1"),
new Tuple<string, string>("A2","B3"),
new Tuple<string, string>("A2","C1"),
new Tuple<string, string>("A2","C3"),
new Tuple<string, string>("A3","B1"),
new Tuple<string, string>("A3","B2"),
new Tuple<string, string>("A3","C1"),
new Tuple<string, string>("A3","C2"),
};
CollectionAssert.AreEquivalent(expected, result);
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.