我有一个二维char数组,叫做Letters [] []
Letters[0][0] = A
[0][1] = B
Letters[1][0] = C
[1][1] = D
Letters[2][0] = B
[2][1] = A
[2][2] = F
Letters[3][0] = I
[3][1] = F
[3][2] = J
我需要对它进行分组,所以它会是这样的:
group[0] [0] = A
group[0] [1] = B
group[0] [2] = F
group[0] [3] = I
group[0] [4] = J
group[1] [0] = C
group[1] [1] = D
到目前为止,我的问题是用其他元素检查每个元素。如果两个元素都是相同的字母,则它与其他所有数组元素组合在一起,没有双重/重复元素。但是,我不确定是否使用C#Linq Union或者只是标准的阵列访问。
我该如何以最佳方式对其进行分组?或者还有其他解决方案吗?
答案 0 :(得分:1)
我认为纯粹的LINQ解决方案会过于复杂。这不是一个简单的联合操作(如果我理解你的规范)。你想基于非空交叉点进行联合。这意味着必须首先重新排列数据,以便LINQ可以进行连接,找到匹配的数据,并且由于LINQ只会加入相等,这样做,同时保留原始分组信息将导致语法更多麻烦比它值得,恕我直言。
这是一个非LINQ方法,适用于您给出的示例:
static void Main(string[] args)
{
char[][] letters =
{
new [] { 'A', 'B' },
new [] { 'C', 'D' },
new [] { 'B', 'A', 'F' },
new [] { 'I', 'F', 'J' },
};
List<HashSet<char>> sets = new List<HashSet<char>>();
foreach (char[] row in letters)
{
List<int> setIndexes = Enumerable.Range(0, sets.Count)
.Where(i => row.Any(ch => sets[i].Contains(ch))).ToList();
CoalesceSets(sets, row, setIndexes);
}
foreach (HashSet<char> set in sets)
{
Console.WriteLine("{ " + string.Join(", ", set) + " }");
}
}
private static void CoalesceSets(List<HashSet<char>> sets, char[] row, List<int> setIndexes)
{
if (setIndexes.Count == 0)
{
sets.Add(new HashSet<char>(row));
}
else
{
HashSet<char> targetSet = sets[setIndexes[0]];
targetSet.UnionWith(row);
for (int i = setIndexes.Count - 1; i >= 1; i--)
{
targetSet.UnionWith(sets[setIndexes[i]]);
sets.RemoveAt(setIndexes[i]);
}
}
}
它通过扫描先前识别的集合来构建输入数据集,以查找当前数据行与哪些集合相交,然后将这些集合合并为包含所有成员的单个集合(您的规范似乎强加了传递成员资格...即如果一个字母加入集合A和B,并且另一个字母加入集合B和C,则希望A,B和C都加入到单个集合中。
这不是最佳解决方案,但它具有可读性。您可以通过维护Dictionary<char, int>
来将每个字符映射到包含它的集合来避免O(N ^ 2)搜索。然后,不是扫描所有集合,而是对当前行中的每个字符进行简单查找,以构建集合索引列表。但是还有很多&#34;内务管理&#34;代码采用这种方法;除非你找到一个经过验证的性能问题,否则我不会那么费心地实现它。
顺便说一句:我有一个模糊的回忆我之前在Stack Overflow上看过这种类型的问题,即这种集合的传递联合。我找了问题,但找不到。您可能会有更多的运气,并且可能会发现该问题及其答案还有其他有用的信息。