Home > Software engineering >  Sorting a text in an optimal order
Sorting a text in an optimal order

Time:06-23

Hi I have a text in a file like this:

Admin,2022-06-23 0:09:47|USER1,2022-06-23 0:09:55|USER3,2022-06-23 0:10:00|Admin,2022-06-23 0:10:05|Admin,2022-06-23 0:10:05|USER1,2022-06-23 0:10:05|

It logs the users when they enter the application.

I want to sort them according to the user and show them as bellow:

Admin:
2022-06-23 0:09:47
2022-06-23 0:10:05
2022-06-23 0:10:05

USER1:
2022-06-23 0:09:55
2022-06-23 0:10:05

USER3:
2022-06-23 0:10:00

Should I use arrays? Now I can get the names and dates, But don't know how to order them as desired:

string lines = File.ReadAllText(@"D:\Docs\Enter.log");
string[] split_arr = lines.Split('|');//files containt ; seprated values
int i = split_arr.Length;
string[] name_arr = new string[i];
string[] date_arr = new string[i];
int j = 0;
var LogString = "";
foreach (string log in split_arr)
{
    name_arr[j] = log.Split(',')[0];
    date_arr[j] = log.Split(',')[1];          
}

This is windows form application.

CodePudding user response:

var data = File.ReadAllText(@"D:\Docs\Enter.log").
            Split('|').
            Select(log => log.Split(',')).
            Where(log => log.Length == 2). //exclude blank value at the end of the data
            GroupBy(log => log[0], log=>DateTime.Parse(log[1])).    
            OrderBy(gr => gr.Key);
        
foreach(var user in result)
{
    Console.WriteLine($"{user.Key}:");
    foreach(var dt in user.OrderBy(x => x))
    {
        Console.WriteLine(dt);
    }
    Console.WriteLine();            
}       

See it work here:

https://dotnetfiddle.net/po9P25

CodePudding user response:

You can use a List:

List<string> mylist = new List<string>(split_arr);
mylist.sort();

foreach (string log in mylist)

So what we do is fill and initiate the List with the string array and then sort it. the foreach will do the rest

CodePudding user response:

'Optimal' depends on the purpose of the method. If your log files are huge or the number of executions can grow unbounded, then memory consumption or execution speed are your 'optimal' metrics. If ease of maintenance or time to market is your priority, then simplicity is your 'optimal' metric.

I'm going to go with a compromise between the two extremes:

Be very careful about reading the whole file in memory, in most real-life scenarios it wouldn't be possible or desirable.

You want to sort the lines by date-time and group them by users, one way to achieve this is as follows:

  1. Create a class to represent your model. It could be as simple as a string property for the user name and a DateTime property for the sign-in time.
  2. After you split the initial file, for each entry you'd like to create an instance of this class. Split the entry by ',', set the user name and for the Date, parse it directly from the string.
  3. After you have created the list of entries, you could use the OrderBy followed by the GroupBy LINQ methods. OrderBy date, GroupBy user name.
  4. The resultant collection has one item for each user name, with a sorted collection of date times.

CodePudding user response:

It's work for current date format

First : define this class

public class LogItem
{
      public string UserName { get; set; }

      public DateTime Date { get; set; }
}

Then : you can use it

List<LogItem> lstLogs = new List<LogItem>();

using (var sr = new StreamReader("logFile.txt"))

{
    var text = sr.ReadToEnd();
    sr.Close(); // close file 


    var logs = text.Split("|");

    foreach (var log in logs)
    {
        // log is not valid ** like end item
        if (log.IndexOf(",") == -1)
            continue; 

        var logSlices = log.Split(",");

        lstLogs.Add(new LogItem
        {
            UserName = logSlices[0],
            Date = DateTime.Parse(logSlices[1])
        });
    }
}

var groupLogs = lstLogs.GroupBy(log => log.UserName)
    .Select(p => new {
        User = p.Key,
        DateEvents = p.OrderBy(l => l.Date).Select(f => f.Date)
    });

foreach (var group in groupLogs)
{
    Console.WriteLine(group.User);
    foreach (var dt in group.DateEvents)
    {
        Console.WriteLine(dt);
    }
}

CodePudding user response:

Having text

string text = @"Admin,2022-06-23 0:09:47|USER1,2022-06-23 0:09:55|USER3,2022-06-23 0:10:00|Admin,2022-06-23 0:10:05|Admin,2022-06-23 0:10:05|USER1,2022-06-23 0:10:05|";

You can try quering with a help of Linq:

using System.Linq;

...

var query = text
  .Split('|', StringSplitOptions.RemoveEmptyEntries)
  .Select(item => item.Split(','))
  .Where(items => items.Length >= 2) 
  .GroupBy(items => items[0], 
           items => DateTime.ParseExact(items[1], "yyyy-M-d H:m:s", null))
  .Select(group => $"{group.Key}:{Environment.NewLine}"   
                     string.Join(Environment.NewLine, group
                       .OrderBy(item => item)
                       .Select(item => $"{item:yyyy-MM-dd H:mm:ss}")));

string report = string.Join(Environment.NewLine   Environment.NewLine, query);

Console.Write(report);

Output:

Admin:
2022-06-23 0:09:47
2022-06-23 0:10:05
2022-06-23 0:10:05

USER1:
2022-06-23 0:09:55
2022-06-23 0:10:05

USER3:
2022-06-23 0:10:00
  •  Tags:  
  • c#
  • Related