【问题标题】:Linq Query Help Needed - Determining Exact Subsets需要 Linq 查询帮助 - 确定确切的子集
【发布时间】:2010-07-13 20:35:22
【问题描述】:

假设我有以下字符串列表:

string[] list1 = { "one", "two", "three", "four"};
string[] list2 = { "one", "two", "three" };
string[] list3 = { "three", "two", "one" };

我需要一个允许我比较 list2 和 list1 的查询,如果 list2 中的所有字符串都存在于 list1 中,则返回 true,与 list2 的顺序相同

因此,如果我将 list2 与 list1 进行比较,这样的查询将返回 true,因为 list2 中的所有字符串都在 list1 中,与 list2 的顺序相同

如果我将 list3 与 list1 进行比较,查询将返回 false,因为即使 list3 中的字符串存在于 list1 中,它们的顺序也不相同

这样的查询可能吗?

【问题讨论】:

  • 如果string[] list1 = { "one", "two", "four", "three"}; compare(list1, list2) 仍然是真的? (技术上与您描述的措辞相符)

标签: linq


【解决方案1】:

如果我明白你在描述什么,应该这样做:

list1.Intersect(list2).SequenceEquals(list2);

我们首先得到list1和list2的intersection,即{ "one", "two", "three" }

然后使用SequenceEquals判断是否与list1相同。

【讨论】:

  • 虽然,我认为它不太符合问题中的情况......“如果我将 list2 与 list1 进行比较,则为 true”
  • @Rex - 这不起作用。当它应该返回 true 时,它​​返回 false。将 list2 与 list1 进行比较应该返回 true,因为 list2 与 list1 在相同的顺序中具有相同的项目。比较 list3 和 list1 应该返回 false,因为即使 list3 包含 list1 中的所有项目,它们的顺序也不相同。
  • @Rex - 实际上你非常接近。以下似乎有效:list2.Intersect(list1).SequenceEqual(list1.Take(list2.Count()))
  • @Randy:我怀疑如果您有重复的元素,这将失败 - Intersect 只返回不同的元素。如果您将“四”移动到第一个元素,它也会在示例案例中失败......我认为它仍然应该匹配,因为 list1 does 按顺序包含 list2 的元素,只是多了一个开始的元素?
  • @Randy 我新修改的代码确实适用于您引用的特定示例,但它可能不适用于某些实际场景。 @Jon 的回答解决了根本问题,而不仅仅是示例案例。
【解决方案2】:

您基本上必须同时遍历两个列表。试试这个:

public static bool IsOrderedSubsequenceOf<T>(
    this IEnumerable<T> smallerList,
    IEnumerable<T> largerList)
{
    IEqualityComparer<T> comparer = Comparer<T>.Default;

    using (var smallerIterator = smallerList.GetEnumerator())
    using (var largerIterator = largerList.GetEnumerator())
    {
        while (smallerIterator.MoveNext())
        {
            T currentTarget = smallerIterator.Current;
            bool found = false;
            while (largerIterator.MoveNext())
            {
                T candidate = largerIterator.Current;
                if (comparer.Equals(currentTarget, candidate))
                {
                    found = true;
                    break;
                }
            }
            if (!found)
            {
                // Exhausted iterator without finding target.
                return false;
            }
        }
    }
    // Found everything in the smaller sequence. Done.
    return true;
}

我没有对此进行测试甚至编译它,但我认为它可能会工作......

你可以这样称呼它

if (list2.IsOrderedSubsequenceOf(list1))

如果你能想出一个更好的名字(可能把论点反过来)那就太好了:)

【讨论】:

  • 我想有朝一日绑架你,交换我们的大脑。我试试这个,谢谢!!
【解决方案3】:

这个怎么样:

int pos = 0;
bool result = list1.Count(p => list2.Contains(p) && pos < list2.Length && list2[pos++] == p) == list2.Length;

我相信这在所有情况下都有效。以下事件:

string[] list1 = { "一", "二", "四", "三" };
string[] list2 = { "一", "二", "三" };

接受的答案将返回 false,即使 list2 中的所有元素都在 list1 中,并且顺序相同。

编辑:如果 list1 在 list2 中包含重复值,则将不起作用。根据下面的 cmets。

【讨论】:

  • 不,string[] list1 = { "three", "one", "two", "four", "three" }; string[] list2 = { "one", "two", "three" }; 失败。它很困惑,因为“三个”在 list2 中,但直到最后......
  • 是的,它失败了,但这是因为 list1 中重复了“三个”。
  • @Klinger:是的,但我看不出问题中的任何内容表明这不是一个有效的案例。
  • @Jon:只是为了争论。 :-) "three", "one", "two", "four", "three" 可能是一个有效的输入,但是,字符串 "three" 是乱序的:"...return true if "all" ...,与 list2 的“顺序相同”。“。我想这个要求需要澄清,因为它为不止一种解释提供了空间。想到三个问题: 1)应该如何处理 list1 中的重复条目。 2) 应如何处理 list2 中的重复条目。 3) list1 中的值可以介于两者之间吗?
  • @Klinger:但是所有值 do 都以相同的顺序出现......它们也以错误的顺序出现,但它们确实以正确的顺序出现。正如您所说,在这里,一些额外的清晰度会有所帮助。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-08-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多