sonnyk2016
sonnyk2016

Reputation: 111

C# Linq that includes sorting and grouping

This is my code:

public class Photos
{
    public long PhotoLabel { get; set; }        
    public int UserID { get; set; }
}

List<Photos> photolist = new List<Photos>();
var result1 = photolist.OrderByDescending(p => p.PhotoLabel).ThenBy(r => r.UserID).ToList();

If I display the contents now, this is what I get (First sorted in descending order of PhotoLabel and then sorted by UserID:

|------|---------------------|---------------------|
| Row  |     UserID          |    PhotoLabel       |
|----------------------------|---------------------|
| 1    |      92             |  20180729181046     |
|----------------------------|---------------------|
| 2    |      92             |  20180729181041     |
|----------------------------|---------------------|
| 3    |      92             |  20180729181037     |
|----------------------------|---------------------|
| 4    |      88             |  20180729174415     |
|----------------------------|---------------------|
| 5    |      88             |  20180729174405     |
|----------------------------|---------------------|
| 6    |      04             |  20180729174358     |
|----------------------------|---------------------|
| 7    |      1              |  20170924183847     |
|----------------------------|---------------------|
| 8    |      1              |  20170921231422     |
|----------------------------|---------------------|
| 9    |      1              |  20170920194624     |
|----------------------------|---------------------|
| 10   |      32             |  20170820114728     |
|----------------------------|---------------------|
| 11   |      32             |  20170820114725     |
|----------------------------|---------------------|
| 12   |      32             |  20170820114421     |
|----------------------------|---------------------|
| 13   |      32             |  20170820114416     |
|----------------------------|---------------------|
| 14   |      1              |  20170225151023     |
|----------------------------|---------------------|
| 15   |      1              |  20170225151000     |
|----------------------------|---------------------|
| 16   |      1              |  20170225150957     |
|----------------------------|---------------------|

From the sorted table above, this is what I want to achieve:

The expected result from query should be:

|------|---------------------|---------------------|
| Row  |     UserID          |    PhotoLabel       |
|----------------------------|---------------------|
| 1    |      92             |  20180729181046     |
|----------------------------|---------------------|
| 2    |      92             |  20180729181041     |
|----------------------------|---------------------|
| 3    |      92             |  20180729181037     |
|----------------------------|---------------------|
| 7    |      1              |  20170924183847     |
|----------------------------|---------------------|
| 8    |      1              |  20170921231422     |
|----------------------------|---------------------|
| 9    |      1              |  20170920194624     |
|----------------------------|---------------------|
| 10   |      32             |  20170820114728     |
|----------------------------|---------------------|
| 11   |      32             |  20170820114725     |
|----------------------------|---------------------|
| 12   |      32             |  20170820114421     |
|----------------------------|---------------------|
| 13   |      32             |  20170820114416     |
|----------------------------|---------------------|

Thank you so much in in advance! :-)

Upvotes: 0

Views: 89

Answers (3)

sonnyk2016
sonnyk2016

Reputation: 111

Thank you all for your help. SKLTFZ's and TanvirArjel's answers were close but didn't achieve the expected results. I realized that you cannot achieve everything described above in Linq, so this is what I came up with and it achieves everything listed above:

PS: I renamed var result1 to ordered_photolist

        List<Photos> ordered_photolist = photolist.OrderByDescending(p => p.PhotoLabel).ThenBy(r => r.UserID).ToList();

        List<Photos> temp_photolist = new List<Photos>();
        List<Photos> final_photolist = new List<Photos>();
        int UserID = -1;
        int UserIDCount = 0;

        foreach (Photos p in ordered_photolist)
        {
            if (UserID == -1)
            {
                UserID = p.UserID;
                temp_photolist.Add(p);
                UserIDCount++;
            }
            else
            {
                if ( UserID == p.UserID )
                {
                    temp_photolist.Add(p);
                    UserIDCount++;
                }
                else
                {
                    if ( UserIDCount >= 3 )
                    {
                        // add temp_photolist to final list
                        int index = final_photolist.FindIndex(item => item.UserID == UserID);
                        if (index == -1)
                        {
                            // element does not exists, do what you need
                            final_photolist.AddRange(temp_photolist);
                        }

                        temp_photolist.Clear();
                        temp_photolist.Add(p);
                        UserIDCount = 1;
                        UserID = p.UserID;
                    }
                    else
                    {
                        temp_photolist.Clear();
                        UserIDCount = 0;
                        UserID = -1;
                    }
                }
            }


        }

Upvotes: 0

TanvirArjel
TanvirArjel

Reputation: 32059

Please wait! This is not the final answer! a little bit further modification is needed! modification is underway.

List<Photos> photolist = new List<Photos>()
        {
            new Photos() {UserID = 92, PhotoLabel = 20180729181046},
            new Photos() {UserID = 92, PhotoLabel = 20180729181041},
            new Photos() {UserID = 92, PhotoLabel = 20180729181037},
            new Photos() {UserID = 88, PhotoLabel = 20180729174415},
            new Photos() {UserID = 88, PhotoLabel = 20180729174405},
            new Photos() {UserID = 04, PhotoLabel = 20180729174358},
            new Photos() {UserID = 1, PhotoLabel = 20170924183847},
            new Photos() {UserID = 1, PhotoLabel = 20170921231422},
            new Photos() {UserID = 1, PhotoLabel = 20170920194624},
            new Photos() {UserID = 32, PhotoLabel = 20170820114728},
            new Photos() {UserID = 32, PhotoLabel = 20170820114725},
            new Photos() {UserID = 32, PhotoLabel = 20170820114421},
            new Photos() {UserID = 32, PhotoLabel = 20170820114416},
            new Photos() {UserID = 1, PhotoLabel = 20170225151023},
            new Photos() {UserID = 1, PhotoLabel = 20170225151000},
        };    

var photolist2 = photolist.GroupBy(g => g.UserID)
                .Select(p => new
                {
                    UserId = p.Key,
                    Count = p.Count()

                })
                .ToList();


var filteredPhotoList = photolist 
            .Join(photolist2, 
                photo => photo.UserID, 
                photo2 => photo2.UserId, 
                (photo, photo2) => new {UserId = photo.UserID, PhotoLabel = 
                photo.PhotoLabel, Count = photo2.Count})
            .Where(p => p.Count > 2).Select(p => new
            {
                p.UserId, p.PhotoLabel
            }).OrderByDescending(p => p.PhotoLabel).ThenBy(p => p.UserId).ToList(); 

Upvotes: 0

SKLTFZ
SKLTFZ

Reputation: 950

If I am not misunderstood the requirement, below function properly works (but it shouldn't the most efficient solution)

protected List<AnObject> aFunction(List<AnObject> sortedList)
{
    //Display groups of UserIDs and PhotoLabels where UserIDs appear 3 or more times in one group (eg: rows 4 and 5 where UserID = 88 and row 6 where UserID = 04 should be eliminated since the UserID = 88 appears just twice in the group and UserID = 04 appears only once in the group).
    //Display only the top most group of UserIDs and exclude any repeating UserIDs(eg: rows 7, 8 and 9 displays the UserID = 1 group.Don't display any other UserID=1 group such as rows 14,15 and 16.
    int pivot = -1;
    int cnt = 0;
    List<AnObject> masterList = new List<AnObject>();
    List<AnObject> subList = new List<AnObject>();
    //List<int> Excluded = new List<int>();
    foreach (AnObject r in sortedList)
    {
        if (pivot != r.UserID)
        {
            if (cnt > 2)
            {
                masterList.AddRange(subList);
                //Excluded.Add(pivot);
            }
            subList.Clear();
            pivot = -1;
            cnt = 0;
            //if (!Excluded.Contains(r.UserID))
            if (!masterList.Any(x => x.UserID == r.UserID))
            {
                pivot = r.UserID;
            }
        }
        subList.Add(r);
        cnt++;
    }
    return masterList;
}

To call it for testing

protected class AnObject
{
    public AnObject(int uid, string photolabel)
    {
        this.UserID = uid;
        this.PhotoLabel = photolabel;
    }
    public int UserID { get; set; }
    public string PhotoLabel { get; set; }
}
protected void Execute()
{
    List<AnObject> sortedList = new List<AnObject>();
    sortedList.Add(new AnObject(92, "anystring"));
    sortedList.Add(new AnObject(92, "anystring"));
    sortedList.Add(new AnObject(92, "anystring"));
    sortedList.Add(new AnObject(88, "anystring"));
    sortedList.Add(new AnObject(88, "anystring"));
    sortedList.Add(new AnObject(4, "anystring"));
    sortedList.Add(new AnObject(1, "anystringfirst"));
    sortedList.Add(new AnObject(1, "anystringfirst"));
    sortedList.Add(new AnObject(1, "anystringfirst"));
    sortedList.Add(new AnObject(32, "anystring"));
    sortedList.Add(new AnObject(32, "anystring"));
    sortedList.Add(new AnObject(32, "anystring"));
    sortedList.Add(new AnObject(32, "anystring"));
    sortedList.Add(new AnObject(1, "anystringafter"));
    sortedList.Add(new AnObject(1, "anystringafter"));
    sortedList.Add(new AnObject(1, "anystringafter"));
    List<AnObject> bb = aFunction(sortedList);
}

Upvotes: 1

Related Questions