【问题标题】:Compare text files in C# and remove duplicate lines比较 C# 中的文本文件并删除重复行
【发布时间】:2017-06-22 14:10:13
【问题描述】:

1.txt

始发地、目的地、日期时间、价格

YYZ,YTC,2016-04-01 12:30,$550
YYZ,YTC,2016-04-01 12:30,$550
LKC,LKP,2016-04-01 12:30,$550

2.txt

始发地|目的地|日期时间|价格

YYZ|YTC|2016-04-01 12:30|$550
AMV|YRk|2016-06-01 12:30|$630
LKC|LKP|2016-12-01 12:30|$990

我有两个带有 ',' 和 '|' 的文本文件作为分隔符,我想在 C# 中创建一个控制台应用程序,当我从命令提示符传递起始和目标位置时读取这两个文件。

在搜索时,我想忽略重复的行,我想按价格顺序显示结果。

输出应该是{ origination } -> { destination } -> datetime -> price

需要帮助如何执行。

【问题讨论】:

  • 你有到目前为止的代码示例吗?
  • 你知道如何阅读文本文件吗?另外,如果您正在创建控制台应用程序,为什么要使用 asp.net 标记它?
  • 了解如何逐行读取文件。了解如何通过给定的分隔符分割字符串:',' 或 '|'等等。学习如何比较字符串。了解如何使用 $ 美元符号和变量的 {} 括号使用字符串插值连接字符串和变量。逐行读取这两个文件。如果字符串不匹配,则拆分并比较字符串,根据它们是否匹配或不使用字符串插值构造您想要的新字符串,附加一个包含两者或仅其中一个的集合。如果您已经知道,请向我们展示一些代码示例,以便我们帮助您改进它们
  • 当我使用 System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().GetName().CodeBase);它给了我错误的路径它显示调试文件夹路径我的文件不在这里 file:\c:\users\502703944\documents\visual studio 2013\Projects\searchTest\searchTest\bin\Debug

标签: c# c#-4.0 console system.io.file


【解决方案1】:

这是一个适用于您的示例文件的简单解决方案。如果文件格式错误,它没有任何错误检查。

using System;
using System.Collections.Generic;

class Program
{
    class entry
    {
        public string origin;
        public string destination;
        public DateTime time;
        public double price;
    }

    static void Main(string[] args)
    {
        List<entry> data = new List<entry>();

        //parse the input files and add the data to a list
        ParseFile(data, args[0], ',');
        ParseFile(data, args[1], '|');

        //sort the list (by price first)
        data.Sort((a, b) =>
        {
            if (a.price != b.price)
                return a.price > b.price ? 1 : -1;
            else if (a.origin != b.origin)
                return string.Compare(a.origin, b.origin);
            else if (a.destination != b.destination)
                return string.Compare(a.destination, b.destination);
            else
                return DateTime.Compare(a.time, b.time);
        });

        //remove duplicates (list must be sorted for this to work)
        int i = 1;
        while (i < data.Count)
        {
            if (data[i].origin == data[i - 1].origin
                && data[i].destination == data[i - 1].destination
                && data[i].time == data[i - 1].time
                && data[i].price == data[i - 1].price)
                data.RemoveAt(i);
            else
                i++;
        }

        //print the results
        for (i = 0; i < data.Count; i++)
            Console.WriteLine("{0}->{1}->{2:yyyy-MM-dd HH:mm}->${3}",
                data[i].origin, data[i].destination, data[i].time, data[i].price);

        Console.ReadLine();
    }

    private static void ParseFile(List<entry> data, string filename, char separator)
    {
        using (System.IO.FileStream fs = System.IO.File.Open(filename, System.IO.FileMode.Open))
        using (System.IO.StreamReader reader = new System.IO.StreamReader(fs))
            while (!reader.EndOfStream)
            {
                string[] line = reader.ReadLine().Split(separator);
                if (line.Length == 4)
                {
                    entry newitem = new entry();
                    newitem.origin = line[0];
                    newitem.destination = line[1];
                    newitem.time = DateTime.Parse(line[2]);
                    newitem.price = double.Parse(line[3].Substring(line[3].IndexOf('$') + 1));
                    data.Add(newitem);
                }
            }
    }
}

【讨论】:

  • 谢谢让我在命令提示符上再试一个问题,用户将添加'$search -o YYZ -d YYC',基于此我需要验证整个过程并需要显示结果如何处理?同样在我的 txt 文件中,我在数据上方有静态标题如何跳过解析该标题?提前致谢
  • 我知道如何跳过的一件事 - reader.ReadLine().Skip(1);但其他命令提示符仍在等待中
【解决方案2】:

我不是 100% 清楚你的程序的输出应该是什么,所以我将把实现的那部分留给你。我的策略是使用一个构造方法,它接受一个字符串(您将从文件中读取)和一个分隔符(因为它会有所不同)并使用它来创建您可以操作的对象(例如添加到哈希集等)。

PriceObject.cs

using System;
using System.Globalization;

namespace ConsoleApplication1
{
class PriceObject
{
    public string origination { get; set; }
    public string destination { get; set; }
    public DateTime time { get; set; }
    public decimal price { get; set; }



    public PriceObject(string inputLine, char delimiter)
    {
        string[] parsed = inputLine.Split(new char[] { delimiter }, 4);
        origination = parsed[0];
        destination = parsed[1];
        time = DateTime.ParseExact(parsed[2], "yyyy-MM-dd HH:mm", CultureInfo.InvariantCulture);
        price = Decimal.Parse(parsed[3], NumberStyles.Currency, new CultureInfo("en-US"));
    }


    public override bool Equals(object obj)
    {
        var item = obj as PriceObject;
        return origination.Equals(item.origination) &&
            destination.Equals(item.destination) &&
            time.Equals(item.time) &&
            price.Equals(item.price);
    }

    public override int GetHashCode()
    {

        unchecked
        {
            var result = 17;
            result = (result * 23) + origination.GetHashCode();
            result = (result * 23) + destination.GetHashCode();
            result = (result * 23) + time.GetHashCode();
            result = (result * 23) + price.GetHashCode();
            return result;
        }
    }


}
}

Program.cs

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;

namespace ConsoleApplication1
{
class Program
{
    static void Main(string[] args)
    {
        HashSet<PriceObject> list1 = new HashSet<PriceObject>();
        HashSet<PriceObject> list2 = new HashSet<PriceObject>();

        using (StreamReader reader = File.OpenText(args[0]))
        {
            string line = reader.ReadLine(); // this will remove the header row

            while (!reader.EndOfStream)
            {
                line = reader.ReadLine();
                if (String.IsNullOrEmpty(line))
                    continue;
                // add each line to our list
                list1.Add(new PriceObject(line, ','));
            }

        }

        using (StreamReader reader = File.OpenText(args[1]))
        {
            string line = reader.ReadLine(); // this will remove the header row

            while (!reader.EndOfStream)
            {
                line = reader.ReadLine();
                if (String.IsNullOrEmpty(line))
                    continue;
                // add each line to our list
                list2.Add(new PriceObject(line, '|'));
            }

        }

        // merge the two hash sets, order by price
        list1.UnionWith(list2);
        List<PriceObject> output = list1.ToList();

        output.OrderByDescending(x => x.price).ToList();

        // display output here, e.g. define your own ToString method, etc
        foreach (var item in output)
        {
            Console.WriteLine(item.ToString());
        }

        Console.ReadLine();
    }
}
}

【讨论】:

  • 请注意,因为根据您的 cmets,您在加载文件时遇到问题:我使用命令行参数运行上述程序:C:\temp\test1.txt C:\temp\test2 .txt
  • 谢谢让我在命令提示符上再试一个问题,用户将添加'$search -o YYZ -d YYC',基于此我需要验证整个过程并需要显示结果如何处理?同样在我的 txt 文件中,我在数据上方有静态标题如何跳过解析该标题?提前致谢
  • 不确定您所说的“验证整个过程”是什么意思,但如果您试图找到匹配的结果,例如起始“YYZ”,目的地“YTC”,您可以将这些参数作为变量放入 linq 查询中。例如。 PriceObject outputObject = output.Where(x =&gt; x.origination.Equals("YYZ") &amp;&amp; x.destination.Equals("YTC")).FirstOrDefault();。为了跳过标题,我在一开始就这样做了:while 循环之前的reader.ReadLine() 将剥离标题。我将编辑评论以使这一点更清楚。
  • 您熟悉从命令行运行控制台应用程序吗?他们真的需要输入“$search”等吗?见这里:stackoverflow.com/questions/12998415/… 如果我是你,我只会将起点和终点存储为变量,例如string origination = args[2] 或其他。
猜你喜欢
  • 2018-12-18
  • 1970-01-01
  • 2021-12-08
  • 1970-01-01
  • 1970-01-01
  • 2011-09-17
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多