尝试基于比较将两个字符串数组合并

3
以下是我的类:
public class Regions
    {
        public int Id { get; set; }
        public string[] ParentName { get; set; }
    }

现在我有两个以上地区类别的列表,如下所示,包含一些数据:
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的末尾

我在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;
        }

请查看左外连接:https://code.msdn.microsoft.com/101-LINQ-Samples-3fb9811b - jdweng
@jdweng:抱歉,但我不认为加入会在这种情况下有所帮助。 - Learning-Overthinker-Confused
@Learning,你确定你的期望输出是正确的吗?第二行不应该是:"Xxx.mp3,rrr.mp3,ggg.mp3,yyy.mp3"吗? - Roman
但是,如果xxx.mp3不在region2中,那么rrr.mp3、ggg.mp3和yyy.mp3怎么办?我想要的是,region1中现有的记录应该保持不变(与region1和region2不匹配)。只有匹配的记录region1和region2应该被合并。 - Learning-Overthinker-Confused
@学习,那么你想要将区域2中存在于区域1中的不同值与区域1合并到一起? - Roman
显示剩余4条评论
3个回答

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
你可以做以下操作:
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"

其实我在想,可以先将两个数组按逗号分割后进行比较,如果字符串的任何部分匹配,则选择计数最高的记录。例如:如果我谈论第一条记录,则Abc.mp3是匹配的,因此来自region2的计数更高,那么就将region2中的记录放入region1中。就像这样。只是一个想法。 - Learning-Overthinker-Confused

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

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


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接