【问题标题】:How to find the placement of a List within another List?如何找到一个列表在另一个列表中的位置?
【发布时间】:2019-05-27 04:24:36
【问题描述】:

我正在处理两个列表。第一个包含大量字符串。第二个包含一个较小的字符串列表。我需要找到第二个列表在第一个列表中的位置。

我使用枚举,由于数据量大,这很慢,我希望有更快的方法。

    List<string> first = new List<string>() { "AAA","BBB","CCC","DDD","EEE","FFF" };

    List<string> second = new List<string>() { "CCC","DDD","EEE" };

int x = SomeMagic(first,second);

我需要 x = 2。

【问题讨论】:

  • 你能告诉我们你到目前为止的尝试吗?

标签: c# list compare


【解决方案1】:

好的,这是我的旧循环变体:

private int SomeMagic(IEnumerable<string> source, IEnumerable<string> target)
{
    /* Some obvious checks for `source` and `target` lenght / nullity are ommited */

    // searched pattern
    var pattern = target.ToArray();
    // candidates in form `candidate index` -> `checked length`
    var candidates = new Dictionary<int, int>();
    // iteration index
    var index = 0;

    // so, lets the magic begin
    foreach (var value in source)
    {
        // check candidates
        foreach (var candidate in candidates.Keys.ToArray()) // <- we are going to change this collection
        {
            var checkedLength = candidates[candidate];
            if (value == pattern[checkedLength]) // <- here `checkedLength` is used in sense `nextPositionToCheck`
            {
                // candidate has match next value
                checkedLength += 1;
                // check if we are done here
                if (checkedLength == pattern.Length) return candidate; // <- exit point
                candidates[candidate] = checkedLength;
            }
            else
                // candidate has failed
                candidates.Remove(candidate);
        }

        // check for new candidate
        if (value == pattern[0])
            candidates.Add(index, 1);
        index++;
    }

    // we did everything we could
    return -1;
}

我们使用候选人字典来处理以下情况:

var first = new List<string> { "AAA","BBB","CCC","CCC","CCC","CCC","EEE","FFF" };
var second = new List<string> { "CCC","CCC","CCC","EEE" };

【讨论】:

    【解决方案2】:

    如果您愿意使用MoreLinq,请考虑使用Window

    var windows = first.Window(second.Count);
    var result = windows
                    .Select((subset, index) => new { subset, index = (int?)index })
                    .Where(z => Enumerable.SequenceEqual(second, z.subset))
                    .Select(z => z.index)
                    .FirstOrDefault();
    
    Console.WriteLine(result);
    Console.ReadLine();
    

    Window 将允许您以块的形式查看数据的“切片”(基于您的second 列表的长度)。然后SequenceEqual可以用来查看切片是否等于second。如果是,则可以返回 index。如果没有找到匹配项,将返回null

    【讨论】:

    • 赞成这个比公认的答案更优雅、更有效的方式
    【解决方案3】:

    实现如下 SomeMagic 方法,如果没有找到匹配则返回 -1,否则返回第一个列表中起始元素的索引。

    private int SomeMagic(List<string> first, List<string> second)
    {
        if (first.Count < second.Count)
        {
            return -1;
        }
    
        for (int i = 0; i <= first.Count - second.Count; i++)
        {
            List<string> partialFirst = first.GetRange(i, second.Count);
            if (Enumerable.SequenceEqual(partialFirst, second))
                return i;
        }
    
        return -1;
    }
    

    【讨论】:

    • 这正是医生所要求的。谢谢。
    • 我建议避免使用GetRange 以避免重复分配列表的成本。 Take 可能会更快。
    【解决方案4】:

    您可以使用命名空间System.Linq 使用相交扩展方法

    var CommonList = Listfirst.Intersect(Listsecond)
    

    【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-07-15
    • 2023-02-25
    • 1970-01-01
    • 1970-01-01
    • 2022-11-12
    • 2014-05-18
    • 1970-01-01
    相关资源
    最近更新 更多