链接一对数字

时间:2018-01-17 13:23:49

标签: c#

我有一对数字列表:

List<Tuple<int, int>> pairs = new List<Tuple<int, int>>();

a. pairs.Add(Tuple.Create<int, int>(1, 2));
b. pairs.Add(Tuple.Create<int, int>(3, 4));
c. pairs.Add(Tuple.Create<int, int>(3, 5));
d. pairs.Add(Tuple.Create<int, int>(5, 6));
e. pairs.Add(Tuple.Create<int, int>(10, 11));
f. pairs.Add(Tuple.Create<int, int>(2, 3));

我希望将它们加入到另一个列表或词典中,如果它们相关则将它们分组。

在上面的示例中,逐步的结果应该是:

一个。 result[0] = {1, 2}
result[0] = {1, 2} result[1] = {3, 4}
C。 result[0] = {1, 2} result[1] = {3, 4, 5}(因为3在那里,所以[1]增加了5) d。 result[0] = {1, 2} result[1] = {3, 4, 5, 6}(自那以后有5人被加入[1]) 即result[0] = {1, 2} result[1] = {3, 4, 5, 6} result[2] { 10, 11 }
F。 result[0] = {1, 2, 3, 4, 5, 6} result[2] { 10, 11 }(3被添加到[0],因为2在那里,这使得[1]与[0]合并,因为3在[1]中)

最终结果:result[0] = {1, 2, 3, 4, 5, 6} result[2] { 10, 11 }

有没有简单的方法可以做到这一点? 感谢

4 个答案:

答案 0 :(得分:0)

以下是名为PairList的列表的实现,该列表具有Add方法,该方法接受元组并执行您想要的操作。

注意:我冒昧地将List<Tuple<int,int>>更改为List<List<int>>,因为您的'对'在加入时可能包含多个数字。

使用示例:

PairList pairs = new PairList();

pairs.Add(Tuple.Create(1, 2));
pairs.Add(Tuple.Create(3, 4));
pairs.Add(Tuple.Create(3, 5));
pairs.Add(Tuple.Create(5, 6));
pairs.Add(Tuple.Create(10, 11));
pairs.Add(Tuple.Create(2, 3));

foreach(List<int> list in pairs) {
    Console.WriteLine(string.Join(",", list));
}
// Output:
// 1,2,3,4,5,6
// 10,11

实现:

public class PairList : List<List<int>>
{
    public void Add(Tuple<int, int> pair)
    {
        // convert from Tuple<int, int> to List<int>
        List<int> newList = new List<int>() { pair.Item1, pair.Item2 };
        newList = newList.OrderBy(i => i).ToList(); // sort

        // tries to join the new list to any of the existing lists
        List<int> joinedList = null;
        for(int i = Count-1; i>=0; --i) {
            if(TryJoin(newList, this[i], out joinedList)) {
                this[i] = joinedList;
                break;
            }
        }

        if(joinedList == null) {
            // the new list was not joined with any of the existing lists
            // so just add it
            Add(newList);
            return;
        }

        // the new list was joined with one of the existing lists
        // so compare all lists with each other and check if they can be joined
        // repeat until no list was joined
        do {
            joinedList = null;
            for(int i = Count-1; i>=0; --i) {
                for(int j = Count-1; j>=0; --j) {
                    if(i == j) continue;

                    if(TryJoin(this[i], this[j], out joinedList)) {
                        this[i] = joinedList;
                        this.RemoveAt(j);
                        // break out of both for loops
                        i = -1;
                        j = -1;
                    }
                }
            }
        } while(joinedList != null);
    }

    private bool TryJoin(List<int> list1, List<int> list2, out List<int> joinedList)
    {
        int low1 = list1[0];
        int low2 = list2[0];
        int high2 = list2.Last();

        // I'm assuming these two conditions are the only valid ones to join
        if(low1 == low2 || low1 == high2){
            joinedList = new List<int>(list1);
            joinedList.AddRange(list2);
            joinedList = joinedList.Distinct().OrderBy(j => j).ToList();
            return true;
        }
        joinedList = null;
        return false;
    }
}

答案 1 :(得分:0)

这会生成您指定的输出 - 但对于大型数据集它不会非常有效!

using System;
using System.Collections.Generic;
using System.Linq;

namespace Demo
{
    class Program
    {
        static void Main()
        {
            var pairs = new List<Tuple<int, int>>
            {
                Tuple.Create(1, 2),
                Tuple.Create(3, 4),
                Tuple.Create(3, 5),
                Tuple.Create(5, 6),
                Tuple.Create(10, 11),
                Tuple.Create(2, 3),
            };

            var groups = new List<List<int>>();

            foreach (var pair in pairs)
            {
                var g1 = groups.Select((g, i) => (g, i)).FirstOrDefault(h => h.g.Contains(pair.Item1));
                var g2 = groups.Select((g, i) => (g, i)).FirstOrDefault(h => h.g.Contains(pair.Item2));

                if (g1.g == null && g2.g == null)
                {
                    groups.Add(new List<int>{ pair.Item1, pair.Item2 });
                }
                else if (ReferenceEquals(g1.g, g2.g)) // Pair already in a single group.
                {
                    // Do nothing.
                }
                else if (g1.g != null && g2.g != null) // Pair appears in two different groups, so join them.
                {
                    g1.g.AddRange(g2.g);
                    g1.g = g1.g.Distinct().ToList();
                    groups.RemoveAt(g2.i);
                }
                else if (g1.g != null) // First of pair appears in g1, so add second of pair.
                {
                    g1.g.Add(pair.Item2);
                }
                else // Second of pair appears in g2, so add first of pair.
                {
                    g2.g.Add(pair.Item1);
                }
            }

            foreach (var group in groups)
            {
                Console.WriteLine(string.Join(", ", group));
            }
        }
    }
}

答案 2 :(得分:0)

这是我第一次尝试它。在此处运行:https://dotnetfiddle.net/Mqq5dQ

using System;
using System.Linq;
using System.Collections.Generic;

public class Program
{
    public static void Main()
    {
        List<Tuple<int, int>> pairs = new List<Tuple<int, int>>();
        pairs.Add(Tuple.Create<int, int>(1, 2));
        pairs.Add(Tuple.Create<int, int>(3, 4));
        pairs.Add(Tuple.Create<int, int>(3, 5));
        pairs.Add(Tuple.Create<int, int>(5, 6));
        pairs.Add(Tuple.Create<int, int>(10, 11));
        pairs.Add(Tuple.Create<int, int>(2, 3));

        var results = new List<List<int>>();
        foreach(var pair in pairs)
        {
            var found = false;
            foreach(var result in results)
            {
                var item1Found = result.Contains(pair.Item1);
                var item2Found = result.Contains(pair.Item2);

                if(item1Found && item2Found){
                    found = true;
                    break;  
                }

                if(item1Found && !item2Found){
                    AddNum(result, results, pair.Item1, pair.Item2);
                    found = true;
                    break;
                }
                if(item2Found && !item1Found){
                    AddNum(result, results, pair.Item2, pair.Item1);
                    found = true;
                    break;
                }
            }
            if(!found){
                results.Add(new List<int> { pair.Item1, pair.Item2 });
            }
        }
        foreach(var result in results)
        {
            Console.WriteLine(string.Join(", ", result.OrderBy(i => i).ToArray()));
        }
    }

    public static void AddNum(List<int> result, List<List<int>> results, int existing, int newnum)
    {
        result.Add(newnum);
        foreach(var otherresult in results){
            if(otherresult != result){
                if(otherresult.Contains(newnum)){
                    var newresult = result.Concat(otherresult).Distinct().ToArray();
                    result.Clear();
                    result.AddRange(newresult);
                    results.Remove(otherresult);
                    break;  
                }
            }
        }
    }
}

答案 3 :(得分:0)

谢谢大家,那很快...... 我之前提出过这个解决方案,我认为有一个更简单的解决方案。你发布的一些代码要好得多,所以我打算带它们。谢谢!

DECLARE @InventoryIDList TABLE(JoiningID INT IDENTITY(1,1), ID INT)
DECLARE @ProductSupplierIDList TABLE(JoiningID INT IDENTITY(1,1), ID INT)

INSERT INTO @InventoryIDList 
VALUES 
(123),
(456),
(789),
(111)

INSERT INTO @productsupplierIDList 
VALUES 
(999),
(888),
(777),
(666)


SELECT i.id, p.id
FROM @inventoryIDList i
INNER JOIN @productsupplierIDList p
    oN i.joiningid = p.JoiningID