Поиск строк в txt — файле с помощью c#

#c# #.net #console-application #txt

Вопрос:

Я работаю над задачей, которая покажет, сколько стран вступило в Европейский союз в 2004 году. Я также хотел бы получить названия стран, которые присоединились к нам в 2004 году. Я начал делать свою работу, но получаю только Кипр. Проблема в том, что в 2004 году к ней присоединились несколько стран. Как получить все названия стран, которые присоединились в 2004 году? Я выполнил свою задачу в консольном приложении (.NET Framework). Для этой задачи я использовал txt-файл, содержащий данные. Вот мой код:

   class Program
    {
        static List<Country> joining = new List<Country>(); 
        static void read()
        {
            string[] rows=File.ReadAllLines("EU.txt");
            foreach (var item in rows)
            {
                joining.Add(new Country(item));
            }
        }
        
        static void Main(string[] args)
        {
            read();
            
            
            
            // how many countries:
            Console.WriteLine($"{joining.Count(item =>item.date.Split('.')[1] == "05" )}countries joined.");
            //names:
            Console.WriteLine($"Country names:{joining.Find(item =>item.date.Split('.')[1] == "05" ).name}"); // !!! this code is bad

    
            Console.ReadKey();
        }
    }

    class Country
    {
        //Fields
        public string date, name;

        //ctor
        public Country(string row)
        {
            name=row.Split(';')[0];
            date = row.Split(';')[1];
        }
    }

 

EU.txt:

Австрия;1995.01.01
Бельгия;1958.01.01
Болгария;2007.01.01
Кипр;2004.05.01
Чехия;2004.05.01
Дания;1973.01.01
Соединенное Королевство;1973.01.01
Эстония;2004.05.01
Финляндия;1995.01.01
Франция;1958.01.01
Греция;1981.01.01
Нидерланды;1958.01.01
Хорватия;2013;07.01
Ирландия;1973.01.01
Польша;2004.05.01
Латвия;2004.05.01
Литва;2004.05.01
Люксембург;1958.01.01
Венгрия;2004.05.01
Мальта;2004.05.01
Германия;1958.01.01
Италия;1958.01.01
Португалия;1986.01.01
Румыния;2007.01.01
Испания;1986.01.01
Швеция;1995.01.01
Шловакия;2004.05.01
Шловения;2004.05.01

Комментарии:

1. joining.Find(...) найдете только первый пункт ( Cyprus в вашем случае).

2. Вы хотите 2004 год или хотите май месяц? Потому что текст вопроса говорит одно, но код вопроса говорит другое.

3. Кроме того, НИКОГДА не публикуйте примеры данных в виде изображения.

Ответ №1:

Ну, joining.Find(...) найдете только первый пункт ( Cyprus в вашем случае). Вместо этого вы можете использовать Linq Where . Пожалуйста, обратите внимание, что вы должны сравнивать с "2004" (годом), а не с "05" (месяцем):

   using System.Linq;

  ...

  // names:
  var names = joining
    .Where(item => item.date.Split('.')[0] == "2004")
    .Select(item => item.name);  

  // let's join all the names by ", ":
  Console.WriteLine($"Country names:{string.Join(", ", names)}"); 
 

Правка: Однако сравнение вроде item.date.Split('.')[1] == "2004" выглядит некрасиво (почему я должен думать о строках при запросе дат?).
Позвольте Country классу помочь самому себе (даты, имена и т.д.):

 class Country {
    public string Name {get;}
    public DateTime JoinedDate {get;}

    public Country(string row) {
      if (row == null)
        throw new ArgumentNullException(nameof(row));  

      string[] items = row.Split(';', 2);

      if (items.Length < 2)
        throw new FormatException("Invalid row format"); 

      Name = items[0];
      JoinedDate = DateTime.ParseExact(items[1], "yyyy.M.d");
    }

    public override string ToString() => Name;
}
 

затем дело доходит до Linq (мы запрашиваем EU.txt файл):

 static void Main(string[] args) {
  List<Country> joined2004 = File
    .ReadLines("EU.txt")
    .Select(line => new Country(line))
    .Where(country => country.JoinedDate.Year == 2004)
    .ToList();

  Console.WriteLine($"{joined2004.Count} countries joined.");
  Console.WriteLine($"{string.Join(", ", joined2004)}")  
}
 

Ответ №2:

Здесь много мелких изменений:

 class Program
{
    static List<Country> Countries; 

    // Use types and methods that avoid needing to load full sets into RAM all at once
    // for as long as possible. That means IEnumerable rather than List and ReadLines() 
    // rather than ReadAllLines().
    // It's also better for the read() function accept a value and return the result
    static IEnumerable<Country> ReadCountries(string filePath)
    {
        // No need to allocate so much RAM via ReadAllLines()
        // Better to just have one line in RAM at a time until everything is loaded
        return File.ReadLines(filePath)
                   .Select(line => new Country(line));
    }
    
    static void Main(string[] args)
    {
        Countries = ReadCountries("EU.txt").ToList();
        var JoinedIn2004 = Countries.Where(c => c.date.Year == 2004);            
        
        Console.WriteLine($"{JoinedIn2004.Count()} countries joined.nCountry name:");
        // need to loop through the list to get all the names
        foreach(var country in JoinedIn2004)
        {
           Console.WriteLine(country.name); 
        }
        // Alternatively, if you really don't want to write a loop:
        // Console.WriteLine(string.Join("n", JoinedIn2004));

        Console.ReadKey(true);
    }
}

class Country
{
    // properties > fields
    public string name {get;set;}
    public DateTime date {get;set;} //Parse an actual DateTime for this!
    
    //personally I lean towards a static builder method (Country.FromTextLine())
    // for this, to decouple building the type from any specific file,
    // but I also get it's overkill here.
    public Country(string row)
    {
        var format = "yyyy.MM.dd";
        var fields = row.Split(';');

        name = fields[0];
        date = DateTime.ParseExact(fields[1], format, null);
    }
}
 

Ответ №3:

     List<Country> result = joining.FindAll(item =>item.date.Split('.')[1] == "05");
    Console.Write($"Country names:");
    foreach(Country country in result)
    {
        Console.Write($"{country.name} ");
    }
    Console.WriteLine();