0

From the client API I get list of data. I have following code, this is a sample code, just need to create sample list to show client data.

class Program
{
    static void Main(string[] args)
    {
        List<Author> authors = new List<Author>
        {
          new Author { Id = "100", Status = "Time (02:15 PM)" , Value = "A" , Test = "B" },
          new Author { Id = "101", Status = "Time (02:16 PM)" , Value = "A" , Test = "B"},
          new Author { Id = "100", Status = "Time (02:10 PM)" , Value = "A" , Test = "B"},
          new Author { Id = "100", Status = "Time (11:15 AM)" , Value = "A" , Test = "B"},
          new Author { Id = "101", Status = "Time (03:40 PM)" , Value = "A" , Test = "B"},
          new Author { Id = "100", Status = "Time (02:15 AM)" , Value = "A" , Test = "B"}
        };

        var aa = authors.ToList();
    }
}

public class Author
{
    public string Id { get; set; }
    public string Status { get; set; }
    public string Value { get; set; }
    public string Test { get; set; }
}

Here I need to get distinct Id with their maximum Status by its time value.

From the output I should need to get this.

  • Id = 100, its maximum Status is : Time (02:15 PM)
  • Id = 101, its maximum Status is : Time (03:40 PM)

How can I do this, its looks something mad, but I need to do this. how can I do this

Updated :

DateTime dt1 = DateTime.Now ;

List<Author> authors = new List<Author>
{
    new Author { Id = "100", Test = "A", dateTime = dt1.AddMinutes(-5) },
    new Author { Id = "101", Test = "K", dateTime = dt1.AddMinutes(-8)  },
    new Author { Id = "100", Test = "C", dateTime = dt1.AddMinutes(-6)  },
    new Author { Id = "100", Test = "D" , dateTime = dt1.AddMinutes(-18)},
    new Author { Id = "101", Status = "G" , dateTime = dt1.AddMinutes(-6)},
    new Author { Id = "100", Status = "Q" , dateTime = dt1.AddMinutes(-3)}
};                     

Updated my question, I added

I added another field called datetime for the ease of the Get max value. Then how can I get maximum datetime for each Id

Output need there two records data,

  • Id = "100", Status = "Q" , dateTime = dt1.AddMinutes(-3)
  • Id = "101", Status = "G" , dateTime = dt1.AddMinutes(-6)
thomsan
  • 433
  • 5
  • 19
  • Check out this https://stackoverflow.com/questions/1101841/how-to-perform-max-on-a-property-of-all-objects-in-a-collection-and-return-th. You could do a GroupBy followed by a MaxBy and then map your string to an int. For example for `Time (02:15 PM)` you could do 02*60 + 15 + 12*60 for "military time" – Brimbo Mar 11 '21 at 14:48

3 Answers3

1

I didn't try but maybe you can split (03:40 PM) part in all statuses and with CultureInfo.InvariantCulture's help you can convert this string to datetime. Then with linq's help you can try something like this:

   var list = authors
        .OrderBy(x => x.Id)
        .ThenByDescending(x => x.Status)
        .GroupBy(x => x.Id)
        .Select(y=> y.FirstOrDefault())
        .ToList();
srls01
  • 425
  • 2
  • 4
  • 12
0
authors.GroupBy(x => int.Parse(x.Id)).Select(x => x.OrderByDescending(y=> DateTime.Parse(y.Status.Substring(6, 8))
).FirstOrDefault());
azuremycry
  • 122
  • 7
0

Apparently Status is a string, but you want to interpret it as a DateTime.

If you can, add a property to your Author:

class Author
{
    ...

    public Datetime StatusTime => // use property Status to extract the Time
}

I assume I don't have to write how you get the Time from the Status string. If that is a challenge for you this will be a nice exercise for you.

If you can't change class Author, consider to create an extension method, so that you can use it, as if it is a method in class Author.

If you are not familiar with extension methods, see Extension methods demystified

public static class AuthorExtensions
{
    public static DateTime GetStatusTime(this Author author)
    {
        // TODO: remove the "Time = ( " part and use DateTime.Parse,
    }
}

Usage:

Author author = ...
DateTime time = author.GetStatusTime();

Once you've got a method like this, the LINQ will be easy: make groups of Authors with same Id, and from every Author in one group, take the Author with the highest value for StatusTime:

IEnumerable<Author> authors = ...
// Make groups of Authors with same Id:
var result = authors.GroupBy(author => author.Id,

    // parameter resultSelector, from every Id, and authors with this Id, 
    // select the author with the highest StatusTime:
    (authorId, authorsWithThisId) => authorWithThisId
        .OrderBy(author => author.GetStatusTime())
        .FirstOrDefault());

It is a bit of a waste, to order the ten Authors in a group if you will be using only the first Author. If performance is an issue, consider to use Aggregate:

(authorId, authorsWithThisId) => authorWithThisId.Aggregate(
    (selectedAuthor, nextAuthor) => (nextAuthor.GetStatusTime() > selectedAuthor.GetStatusTime()) ?
        nextAuthor : selectedAuthor);

This will still translate the Status into StatusTime several times, so the optimal method:

var result = authors.Select(author => new
{
    Id = author.Id,
    StatusTime = author.GetStatusTime(),
})
.GroupBy(author => author.Id)
.Select(authorGroup => authorGroup.Aggregate(
    (x, y) => (x.StatusTime > y.StatusTime) ? x, y);
Harald Coppoolse
  • 28,834
  • 7
  • 67
  • 116