我有2个 csv 文件
1.csv
accepts_nested_attributes_for
2.csv
spain;russia;japan
italy;russia;france
我读了两个文件并将数据添加到列表中
spain;russia;japan
india;iran;pakistan
然后我找到两个列表中的所有唯一字符串并将其添加到结果列表
var lst1= File.ReadAllLines("1.csv").ToList();
var lst2= File.ReadAllLines("2.csv").ToList();
rezlist包含此数据
var rezList = lst1.Except(lst2).Union(lst2.Except(lst1)).ToList();
现在我想在所有行中通过第二和第三列进行比较,制作除外和并用。
1.csv
西班牙;的俄罗斯;日本
意大利;的俄罗斯;法国
2.csv
西班牙;的俄罗斯;日本
印度;的伊朗;巴基斯坦
我想我需要按符号';'拆分所有行并进行所有 3 操作(除,不同和联盟),但无法理解。
[0] = "italy;russia;france"
[1] = "india;iran;pakistan"
必须包含
rezlist
我添加了课程
india;iran;pakistan
答案 0 :(得分:4)
您的问题不是很清楚:例如,india;iran;pakistan
所需的结果主要是因为俄罗斯位于元素[1]?还包括因为元素[2] 巴基斯坦与法国和日本不匹配?即使这些不清楚,我认为所期望的结果来自任何一种情况。
然后就是: 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:
NepalX
和ItalyX
是两个文件中的重复内容,它们正确地相互消除。
每一步都是扫描并使用越来越少的数据,这似乎使得65,000行/ 130,000个数据元素的速度非常快。
答案 1 :(得分:0)
你的GetHashCode()
- EqualityComparer中的方法有问题。修正版:
public int GetHashCode(string obj)
{
return obj.Split(';')[1].GetHashCode();
}
现在结果是正确的:
// one result: "india;iran;pakistan"
顺便说一句。 "StringLengthEqualityComparer"
不是一个好名字; - )
答案 2 :(得分:0)
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);
}
}
}
}
答案 3 :(得分:0)
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);
}
}
}