【问题标题】:How to compare two csv files by 2 columns?如何按 2 列比较两个 csv 文件?
【发布时间】:2016-08-19 19:37:43
【问题描述】:

我有 2 个 csv 文件

1.csv

spain;russia;japan
italy;russia;france

2.csv

spain;russia;japan
india;iran;pakistan

我读取了两个文件并将数据添加到列表中

var lst1= File.ReadAllLines("1.csv").ToList();
var lst2= File.ReadAllLines("2.csv").ToList();

然后我从两个列表中找到所有唯一字符串并将其添加到结果列表中

var rezList = lst1.Except(lst2).Union(lst2.Except(lst1)).ToList();

rezlist 包含此数据

[0] = "italy;russia;france"
[1] = "india;iran;pakistan"

现在我想在所有行中通过 secondthird 列来比较、制作除外和联合。

1.csv

西班牙;俄罗斯;日本

意大利;俄罗斯;法国

2.csv

西班牙;俄罗斯;日本

印度;伊朗;巴基斯坦

我想我需要用符号';'分割所有行并进行所有 3 操作(exceptdistinctunion),但不知道如何操作。

rezlist 必须包含

india;iran;pakistan

我添加了类

 class StringLengthEqualityComparer : IEqualityComparer<string>
        {

            public bool Equals(string x, string y)
            {
               ...
            }

            public int GetHashCode(string obj)
            {
               ...
            }
        }



 StringLengthEqualityComparer stringLengthComparer = new StringLengthEqualityComparer();
 var rezList = lst1.Except(lst2,stringLengthComparer ).Union(lst2.Except(lst1,stringLengthComparer),stringLengthComparer).ToList();

【问题讨论】:

  • 你有没有尝试过?
  • 时刻。我添加了一些代码
  • 你能举例说明这个程序应该做什么吗?
  • 我将它添加到代码中。程序必须返回印度;伊朗;巴基斯坦
  • 能否请您扩展更多输出示例。还请提供一些关于如何创建结果的规则

标签: c# list compare


【解决方案1】:

您的问题不是很清楚:例如,india;iran;pakistan 是否主要是因为 russia 位于元素 [1] 中?不也是因为元素 [2] pakistan 不匹配 francejapan 吗?尽管不清楚,但我认为所需的结果来自任何一种情况。

然后是这个:find all unique string from both lists,它极大地改变了自然。因此,我认为所需的结果是因为“伊朗”出现在列 [1] 中,而没有出现在列 [1] 中的任何一个文件中的其他位置,即使它出现了,由于 col 中的“巴基斯坦”,该行仍然是唯一的[2]。

另请注意,2 的数据样本留有相当多的错误空间。

尝试一步完成会让人很困惑。由于消除 1.CSV 中的欺骗非常容易,所以先做吧:

// parse "1.CSV"
List<string[]> lst1 = File.ReadAllLines(@"C:\Temp\1.csv").
            Select(line => line.Split(';')).
            ToList();

// parse "2.CSV"
List<string[]> lst2 = File.ReadAllLines(@"C:\Temp\2.csv").
            Select(line => line.Split(';')).
            ToList();

// extracting once speeds things up in the next step
//  and leaves open the possibility of iterating in a method
List<List<string>> tgts = new List<List<string>>();
tgts.Add(lst1.Select(z => z[1]).Distinct().ToList());
tgts.Add(lst1.Select(z => z[2]).Distinct().ToList());

var tmpLst = lst2.Where(x => !tgts[0].Contains(x[1]) ||
                !tgts[1].Contains(x[2])).
                ToList();

这会导致项目不在 1.CSV 中(在 Col[1] 和 Col[2] 中没有匹配的文本)。如果这确实是您所需要的,那么您就完成了。

在 2.CSV 中获取唯一行比较棘手,因为您必须实际计算每个 Col[1] 项出现的次数以查看它是否唯一;然后重复 Col[2]。这使用 GroupBy:

var unique = tmpLst.
    GroupBy(g => g[1], (key, values) =>
            new GroupItem(key, 
                    values.ToArray()[0], 
                    values.Count())
            ).Where(q => q.Count == 1).
    GroupBy(g => g.Data[2], (key, values) => new
            {
                Item = string.Join(";", values.ToArray()[0]),
                Count = values.Count()
            }
            ).Where(q => q.Count == 1).Select(s => s.Item).
        ToList();

GroupItem 类很简单:

class GroupItem
{
    public string Item { set; get; }      // debug aide
    public string[] Data { set; get; }
    public int Count { set; get; }
            
    public GroupItem(string n, string[] d, int c)
    {
        Item = n;
        Data =  d;
        Count = c;
    }
    public override string ToString()
    {
        return string.Join(";", Data);
    }
}

它以tmpList 开头,获取在[1] 处具有唯一元素的行。它使用一个类进行存储,因为此时我们需要数组数据进行进一步审查。

第二个GroupBy 作用于这些结果,这次查看 col[2]。最后,它选择连接的字符串数据。

结果

在 File1 (1.3 MB) 中使用 50,000 个随机项目,在 File2 (390 kb) 中使用 15,000 个。没有自然产生的唯一项,所以我在 2.CSV 中手动制作了 8 个唯一项,并将其中的 2 个复制到 1.CSV 中。如果 2.CSV 中的 8 个唯一行使预期结果为 6 个唯一行,则 1.CSV 中的副本应消除 2:

NepalXItalyX 是两个文件中的重复,它们正确地相互消除了。

每一步它都在扫描和处理越来越少的数据,这对于 65,000 行/130,000 个数据元素来说似乎相当快。

【讨论】:

  • 感谢回复。一切都很好,但速度非常非常慢。我在两个 csv 文件中都有 300k 数据。如何提高速度?
  • 是的,这就是小测试数据集的问题。更新了答案。钻入数组很慢,测试重复元素也很慢。正如它所说,它现在可以在大约 150 毫秒内处理比您的文件更大的文件。
【解决方案2】:

你在 EqualityComparer 中的 GetHashCode()-Method 有问题。固定版本:

public int GetHashCode(string obj)
{
  return obj.Split(';')[1].GetHashCode();
}

现在结果是正确的:

// one result: "india;iran;pakistan"

顺便说一句。 "StringLengthEqualityComparer"不是一个好名字;-)

【讨论】:

  • 谢谢,另一个问题。如何按第二列和第三列比较字符串?
  • [1] 已经比较了第二列,第一列使用[0] 第三列[2]。更改 Equals()GetHashCode() 方法中的括号值。
  • 如何制作?你能分享exampleS吗?
【解决方案3】:
private void GetUnion(List<string> lst1, List<string> lst2)
{
    List<string> lstUnion = new List<string>();
    foreach (string value in lst1)
    {
        string valueColumn1 = value.Split(';')[0];
        string valueColumn2 = value.Split(';')[1];
        string valueColumn3 = value.Split(';')[2];

        string result = lst2.FirstOrDefault(s => s.Contains(";" + valueColumn2 + ";" + valueColumn3));

        if (result != null)
        {
            if (!lstUnion.Contains(result))
            {
                lstUnion.Add(result);
            }                   
        }
    }
}

【讨论】:

    【解决方案4】:
      class Program
        {
            static void Main(string[] args)
            {
                var lst1 = File.ReadLines(@"D:\test\1.csv").Select(x => new StringWrapper(x)).ToList();
                var lst2 = File.ReadLines(@"D:\test\2.csv").Select(x => new StringWrapper(x));
                var set = new HashSet<StringWrapper>(lst1);
                set.SymmetricExceptWith(lst2);
    
                foreach (var x in set)
                {
                    Console.WriteLine(x.Value);
                }
    
            }
        }
    
        struct StringWrapper : IEquatable<StringWrapper>
        {
            public string Value { get; }
            private readonly string _comparand0;
            private readonly string _comparand14;
    
            public StringWrapper(string value)
            {
                Value = value;
                var split = value.Split(';');
                _comparand0 = split[0];
                _comparand14 = split[14];
            }
    
            public bool Equals(StringWrapper other)
            {
                return string.Equals(_comparand0, other._comparand0, StringComparison.OrdinalIgnoreCase)
                       && string.Equals(_comparand14, other._comparand14, StringComparison.OrdinalIgnoreCase);
            }
    
            public override bool Equals(object obj)
            {
                if (ReferenceEquals(null, obj)) return false;
                return obj is StringWrapper && Equals((StringWrapper) obj);
            }
    
            public override int GetHashCode()
            {
                unchecked
                {
                    return ((_comparand0 != null ? StringComparer.OrdinalIgnoreCase.GetHashCode(_comparand0) : 0)*397)
                           ^ (_comparand14 != null ? StringComparer.OrdinalIgnoreCase.GetHashCode(_comparand14) : 0);
                }
            }
        }
    

    【讨论】:

    • 为什么是这个答案?并且没有解释。来吧伙计们!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-04-27
    • 1970-01-01
    • 1970-01-01
    • 2019-01-19
    • 1970-01-01
    相关资源
    最近更新 更多