【问题标题】:Is there any c# function for making a set closed under union/intersection是否有任何 c# 函数可以在联合/交集下关闭集合
【发布时间】:2019-08-22 10:39:43
【问题描述】:

我正在制作一个在 union 下关闭的字符串数组列表,这意味着任何两个数组的 union 都必须在完整列表中。

为此,我编写了自己的代码,该代码遍历字符串数组列表并添加新字符串数组,这些新字符串数组是列表中两个现有字符串数组的并集,仅当新数组不存在于列表。

public static List<string[]> UnionClosed(List<string[]> kstructure)
{        
    for (int i = 1; i < kstructure.Count; i++)
    {
        for (int j = i + 1; j < kstructure.Count; j++)
        {
            string[] kstate1 = kstructure[i];
            string[] kstate2 = kstructure[j];
            string[] unionStatesResult = kstate1.Union(kstate2).ToArray();
            int flag = 0;
            for (int k = 1; k < kstructure.Count; k++)
            {
                if (kstructure[k].Length == unionStatesResult.Length && kstructure[k].Intersect(unionStatesResult).Count()==kstructure[k].Length)
                {
                    flag = flag + 1;
                    break;
                }

            }
            if (flag==0)
            {
                kstructure.Add(unionStatesResult);
            }
        }
    }

    return (kstructure);
}

预期的结果是得到一个在union下闭合的字符串数组列表。

例如,如果我传递输入:{{}, {"i1"}, {"i2"}, {"i3"}, {"i4"}, {"i1","i2"}, { “i1”、“i3”}、{“i1”、“i4”}、{“i1”、“i5”}、{“i2”、“i3”}、{“i2”、“i4”}、{ “i2”、“i5”}、{“i1”、“i2”、“i3”}、{“i1”、“i2”、“i4”}、{“i1”、“i2”、“i5”} , {"i1", "i3", "i4"}, {"i1", "i3", "i5"}, {"i2", "i3","i4"}, {"i2","i3 ","i5"},{"i1", "i2", "i3", "i4"}, {"i1", "i2", "i3", "i5"}, {"i1", "i3 "、"i4"、"i5"}、{"i1"、"i2"、"i3"、"i4"、"i5"}}。

那么预期的输出应该是:{{}, {"i1"}, {"i2"}, {"i3"}, {"i4"},{"i1","i2"}, {" i1", "i3"}, {"i1", "i4"}, {"i1", "i5"},{"i2", "i3"}, {"i2","i4"}, {" i2”、“i5”}、{“i3”、“i4”}、{“i1”、“i2”、“i3”}、{“i1”、“i2”、“i4”}、{“i1” ,“i2”,“i5”},{“i1”,“i3”,“i4”},{“i1”,“i3”,“i5”},{“i1”,“i4”,“i5” },{“i2”,“i3”,“i4”},{“i2”,“i3”,“i5”},{“i2”,“i4”,“i5”},{“i1”,“ i2"、"i3"、"i4"}、{"i1"、"i2"、"i3"、"i5"}、{"i1"、"i2"、"i4"、"i5"}、{" i1”、“i3”、“i4”、“i5”}、{“i2”、“i3”、“i4”、“i5”}、{“i1”、“i2”、“i3”、“i4” ,"i5"}}。

我得到了输出,但问题是它非常慢,而且它没有为大量字符串数组提供结果。我想在联合下关闭一个大小为 500 的列表,但这段代码没有为我提供结果。我想知道是否有任何 c# 功能可以做同样的事情。其中,R sets 包在 binary_closure() 下提供了相同的功能。我想在 c# 中做同样的事情。

【问题讨论】:

  • 如果您能提供minimal reproducible example,那就太好了。请务必包含示例输入以及基于这些示例输入的预期结果
  • NuGet, tagged statistics 中的任何软件包有帮助吗?
  • 我尝试了那个联合方法。问题是一样的,大数据的代码很慢。我正在寻找一种可以使我的列表在联合下关闭的功能。在 R 中,有一个包“sets”提供了名为 binary_closure 的相同功能,速度非常快。我想要 c# 中的相同功能。我搜索了很多,但没有运气。
  • @Hans k esting ,我在 NuGet 包中找不到任何功能,请您给我任何提示,告诉我哪个包可以提供我正在寻找的相同功能。
  • @Mahakgarg 请将示例输入和输出添加到您的问题中。

标签: c# r set closures


【解决方案1】:

您可以通过使用 HashSet 进行集合比较来提高效率,而不是进行循环。

首先,来自您的一个 cmets 的输入:

var input = new string[][]
{
    new string[0],
    new[] {"i1"},
    new[] {"i2"},
    new[] {"i3"},
    new[] {"i4"},
    new[] {"i1", "i2"},
    new[] {"i1", "i3"},
    new[] {"i1", "i4"},
    new[] {"i1", "i5"},
    new[] {"i2", "i3"},
    new[] {"i2", "i4"},
    new[] {"i2", "i5"},
    new[] {"i1", "i2", "i3"},
    new[] {"i1", "i2", "i4"},
    new[] {"i1", "i2", "i5"},
    new[] {"i1", "i3", "i4"},
    new[] {"i1", "i3", "i5"},
    new[] {"i2", "i3", "i4"},
    new[] {"i2", "i3", "i5"},
    new[] {"i1", "i2", "i3", "i4"},
    new[] {"i1", "i2", "i3", "i5"},
    new[] {"i1", "i3", "i4", "i5"},
    new[] {"i1", "i2", "i3", "i4", "i5"},
};

我们需要一个这样的助手,它可以让我们比较 HashSet 的相等性:

public class HashSetEqualityComparer<T> : IEqualityComparer<HashSet<T>>
{
    public static readonly HashSetEqualityComparer<T> Instance = new HashSetEqualityComparer<T>();

    public bool Equals(HashSet<T> x, HashSet<T> y)
    {
        if (ReferenceEquals(x, y))
            return true;
        if (ReferenceEquals(x, null) || ReferenceEquals(y, null))
            return false;

        return x.SetEquals(y);
    }

    public int GetHashCode(HashSet<T> obj)
    {
        // See http://stackoverflow.com/a/670068/1086121

        if (obj == null)
            throw new ArgumentNullException(nameof(obj));

        var comparer = obj.Comparer;
        int hash = 0;
        foreach (T element in obj)
        {
            hash = unchecked(hash + comparer.GetHashCode(element));
        }
        return hash;
    }
}

然后,代码:

var output = new HashSet<HashSet<string>>(HashSetEqualityComparer<string>.Instance);

for (int i = 0; i < input.Length; i++)
{
    // We need to make sure that every input item is in the output
    output.Add(new HashSet<string>(input[i]));

    for (int j = i + 1; j < input.Length; j++)
    {
        // It annoys me that we have to create a HashSet<string>(input[i]))twice
        var hashSet = new HashSet<string>(input[i]);
        hashSet.UnionWith(input[j]);
        output.Add(hashSet);
    }
}

对于第一个和第二个字符串的每个组合,我们创建一个新的 HashSet。然后我们尝试将HashSet&lt;string&gt; 添加到我们的HashSet 输出中,即HashSet&lt;HashSet&lt;string&gt;&gt;。我们的自定义 IEqualityComparer 将确保仅在它不存在时才添加它。

我们还将输入和输出集合分开,因此我们不会像输入一样开始处理输出(这会增加很多不必要的工作)。

【讨论】:

  • 非常感谢您的回复。
  • @Mahakgarg 如果您发现有用的答案,请考虑对其进行投票。如果答案回答了您的问题,请考虑接受。
  • 您的代码肯定比我的要快,但这种方法仍然很慢。如果集合中有大量元素,我不会得到输出。有没有其他可能的方法?
  • 在R中,“sets”包函数binary_closure通过ac代码做同样的事情,当我试图通过构造c dll然后在c#代码中调用它来做同样的事情时,我得到了很多错误在读取源文件时。如果您知道有什么可以解决的,请提出建议。
猜你喜欢
  • 1970-01-01
  • 2014-03-10
  • 2022-01-04
  • 2019-09-20
  • 1970-01-01
  • 1970-01-01
  • 2015-06-06
  • 1970-01-01
相关资源
最近更新 更多