【问题标题】:Comparing two hashsets比较两个哈希集
【发布时间】:2012-05-22 15:09:23
【问题描述】:

我有两个哈希集从两个不同的文本文件加载数据。 两个文本文件的内容如下:

name/12441431252132
name1/323244231244142
name2/32423452524234

我的代码当前加载这两个文件并确保我只有来自 textFile2 的唯一结果:

HashSet<string> txt1 = new HashSet<string>(File.ReadLines("textFile1.txt"));
HashSet<string> txt2 = new HashSet<string>(File.ReadLines("textFile2.txt"));

txt2.ExceptWith(txt1); 

我的问题是,如果整行匹配,它只会根据条件删除行。我想改为根据名称删除它。例如,如果 name2 在 textFile1 中,则永远不应包含它,即使 / 之后的 id 不同。

我将如何做到这一点?

如果我的解释不好,请告诉我,我会努力改进它 - 请原谅我的英语!

【问题讨论】:

  • 每个文本文件中的名称是否唯一?
  • 在 textfile1 中并不总是可以有超过 1 个相同的,但如果是,则永远不应在 txt2 中的 exceptWith 之后包含它

标签: c#


【解决方案1】:

您可以添加一些字符串拆分来分隔名称和其余内容 - 这种方法有点“脏”,所以在实际代码中我可能会使用 foreach 循环并引入专用类:

var content = File.ReadLines("textFile1.txt").Select(line => 
{
    var parts = line.Split('/');
    return new 
    { 
        Name = parts[0],
        Content = parts[1]
    };
});

HashSet<string> names = new HashSet<string>(content.Select(c=> c.Name));
HashSet<string> txt2 = new HashSet<string>(File.ReadLines("textFile2.txt"));
var uniques = txt2.Where(line => !names.Contains(line.Split('/')[0]));

【讨论】:

  • 如何从 uniques var 中获取第一个唯一名称和 ID?稍后在代码中我需要使用第一个并将它们变成字符串
  • @hariette:我不清楚您是否也想将txt2 的行分隔成名称/值对 - 在这种情况下,只需使用与用于contents解析
【解决方案2】:

如果您按/ 拆分,您可以构建一个包含出现在第一个集合中的名称的 HashSet,然后选择第二个集合中名称未出现在第一个集合中的项目。

var nameValues1=
    File
     .ReadLines(fileName)
     .Select(line=>line.Split('/'))
     .Select(parts=>new {name=parts[0],value=parts[1]});
var nameValues2=
    File
     .ReadLines(fileName2)
     .Select(line=>line.Split('/'))
     .Select(parts=>new {name=parts[0],value=parts[1]});
var names1=new HashSet<string>(nameValues1.Select(nv=>nv.name);
var result=
    nameValues2
     .Where(nv=>!names1.Contains(nv.name))
     .Select(nv=>string.Format("{0}/{1}",nv.name,nv.value);

【讨论】:

    【解决方案3】:

    您确定HashSet 仍然是最佳选择吗?这是使用Dictionary&lt;String, String&gt; 的另一种方法:

    var lines1 = System.IO.File.ReadLines(path1);
    var lines2 = System.IO.File.ReadLines(path2);
    var allItems = new Dictionary<String, String>();
    foreach (var line in lines1.Concat(lines2))
    {
        String[] tokens = line.Split('/');
        if (tokens.Length == 2)
        {
            String name = tokens[0];
            String number = tokens[1];
            if (!allItems.ContainsKey(name))
                allItems.Add(name, number);
        }
    }
    

    【讨论】:

    • 这是有问题的,因为 OP 声明文件中的名称不是唯一的。
    • @spender:但他的要求是过滤掉重复的名字。上述方法将覆盖现有名称的数字,但可以轻松更改以执行其他操作。
    • @spender:由于 OP 只想拿第一个,我在上面进行了编辑以使用 ContainsKey 检查是否存在。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-09-05
    • 2016-09-05
    • 2016-09-13
    相关资源
    最近更新 更多