尝试根据比较合并两个字符串数组

时间:2017-03-07 15:25:55

标签: c# linq

以下是我的课程:

public class Regions
    {
        public int Id { get; set; }
        public string[] ParentName { get; set; }
    }

现在我有2个上面的区域列表,如下所示,包含一些数据:

var region1 = new Regions();
var region2 = new Regions();

现在 ParentName 包含 region1 的以下数据:

[0] : Abc.mp3,Pqr.mp3
[1] : Xxx.mp3
[2] : kkk.mp3
[3] : ppp.mp3,zzz.mp3,rrr.mp3,ddd.mp3

现在 ParentName 包含 region2 的以下数据:

[0] : Abc.mp3,Pqr.mp3,lmn.mp3
[1] : rrr.mp3,ggg.mp3,yyy.mp3

现在我尝试将region2的ParentName合并到region1中,如果在使用逗号分割记录之后,region1的任何部分与region2匹配:

[0] : Abc.mp3,Pqr.mp3,lmn.mp3
[1] : Xxx.mp3
[2] : kkk.mp3
[3] : ppp.mp3,zzz.mp3,rrr.mp3,ddd.mp3,ggg.mp3,yyy.mp3

现在在上面的预期输出中, Abc.mp3和Pqr.Mp3(Region1和Region2)仅匹配Lmn.mp3不匹配,因此它将附加在Region1 的末尾。

对于region1和region2的最后一条记录, rrr.mp3是匹配的(单一匹配也足够了)所以来自region2的非匹配记录,即ggg.mp3,yyy.mp3将附加在region1的末尾< / em>的

输出我在Region1:

[0] : Abc.mp3,Pqr.mp3
[1] : Xxx.mp3
[2] : kkk.mp3
[3] : ppp.mp3,zzz.mp3,rrr.mp3,ddd.mp3
[4] : Abc.mp3,Pqr.mp3,lmn.mp3
[3] : rrr.mp3,ggg.mp3,yyy.mp3

代码:

region1.ParentName = region1.ParentName.Concat(region2.ParentName).Distinct().ToArray();


public static T[] Concat<T>(this T[] x, T[] y)
        {
            if (x == null) throw new ArgumentNullException("x");
            if (y == null) throw new ArgumentNullException("y");
            int oldLen = x.Length;
            Array.Resize<T>(ref x, x.Length + y.Length);
            Array.Copy(y, 0, x, oldLen, y.Length);
            return x;
        }

3 个答案:

答案 0 :(得分:1)

您可以使用Split()方法获取字符串的一部分并查找匹配项,并使用Join()方法获取最终字符串:

private static void Merge(Regions region, Regions region2)
{
    List<List<string>> splittedLists = region.ParentName.Select(p => p.Split(new char[] { ',' }, StringSplitOptions.None).ToList()).ToList();
    List<List<string>> splittedLists2 = region2.ParentName.Select(p => p.Split(new char[] { ',' }, StringSplitOptions.None).ToList()).ToList();
    List<string> res = new List<string>();

    foreach (var item in splittedLists)
    {
        bool wasMatch = false;           
        foreach (var s in item)
        {
            bool contains = false;
            foreach (var s2 in splittedLists2.Where(s2 => s2.Contains(s)))
            {
                wasMatch = true;
                contains = true;
                res.Add(string.Join(",", item.Concat(s2).Distinct()));
            }    
            if (contains)
            {
                contains = false;
                break;
            }
        }    
        if (!wasMatch)
        {
            res.Add(string.Join(",", item));
        }
    }    
    region.ParentName = res.ToArray();
}

答案 1 :(得分:1)

您可以执行以下操作:

public static void Merge(Regions first, Regions second)
{
    if (ReferenceEquals(first, null))
        throw new ArgumentNullException(nameof(first));

    if (ReferenceEquals(second, null))
        throw new ArgumentNullException(nameof(second));

    first.ParentName = first.ParentName.Merge(second.ParentName).ToArray();
}

private static IEnumerable<string> Merge(this IEnumerable<string> first, IEnumerable<string> second)
{
    if (ReferenceEquals(first, null))
        throw new ArgumentNullException(nameof(first));

    if (ReferenceEquals(second, null))
        throw new ArgumentNullException(nameof(second));

    foreach (var f in first)
    {
        yield return f.Merge(second, ',');
    }
}

private static string Merge(this string first, IEnumerable<string> second, char separator)
{
    Debug.Assert(first != null);
    Debug.Assert(second != null);

    var firstSplitted = first.Split(separator);

    foreach (var s in second)
    {
        var sSplitted = s.Split(separator);

        if (firstSplitted.Intersect(sSplitted).Any())
            return string.Join(separator.ToString(), firstSplitted.Union(sSplitted));
    }

    return first;
}

请注意,这会在找到的第一个匹配项上合并;如果存在重复值,则只会在第一次遇到匹配时合并。

这里的秘密是分而治之。如果您在实现某个逻辑时遇到问题,那么将其分解为更简单的步骤并为每个婴儿步骤实施一个方法。一旦它工作,如果你真的需要,你可以重构你的代码,使其更简洁或高效。

如果你运行:

var first = new Regions();
var second = new Regions();
first.ParentName = new[] { "Abc.mp3,Pqr.mp3", "Xxx.mp3", "kkk.mp3", "ppp.mp3,zzz.mp3,rrr.mp3,ddd.mp3" };
second.ParentName = new[] { "Abc.mp3,Pqr.mp3,lmn.mp3", "rrr.mp3,ggg.mp3,yyy.mp3" };
Merge(first, second);

您将获得预期的结果。 first.ParentName将是:

[0]: "Abc.mp3,Pqr.mp3,lmn.mp3"
[1]: "Xxx.mp3"
[2]: "kkk.mp3"
[3]: "ppp.mp3,zzz.mp3,rrr.mp3,ddd.mp3,ggg.mp3,yyy.mp3"

答案 2 :(得分:1)

目前还不清楚你的名字是否包含重复项以及如何处理它们,但这里是LINQ解决方案,它使用指定的输入产生所需的结果:

var e2Sets = region2.ParentName.Select(e2 => e2.Split(',')).ToList();
var result =
    from e1 in region1.ParentName
    let e1Set = e1.Split(',')
    let e2AppendSet = (
       from e2Set in e2Sets
       where e1Set.Intersect(e2Set).Any()
       from e2New in e2Set.Except(e1Set)
       select e2New
    ).Distinct()
    select string.Join(",", e1Set.Concat(e2AppendSet));

result.ToArray()会为您提供所需的新region1.ParentName

工作原理:

由于我们基本上需要两个输入序列的笛卡尔积,我们首先准备第二个序列的分裂字符串数组列表,以避免内部循环内的多个string.Split

对于第一个序列的每个元素,我们将其拆分为字符串数组,对于第二个序列中的每个拆分数组,其具有匹配(使用Intersect方法确定),我们使用以下方法选择不匹配的字符串Except方法。然后我们展平所有不匹配的字符串,应用Distinct删除潜在的重复项,连接两个集合并使用string.Join生成新的逗号分隔字符串。