0

I would like to Lambda my code but am stuck.

Basically: If the array object contains say 4 members with their own year specification and id's. The array can however contain many more members with the same and different Id's and year (never same Id and same year though).

Member array:

array[0]: Id 1 Year 2010
array[1]: Id 2 Year 2010
array[2]: Id 1 Year 2008
array[3]: Id 1 Year 2009

First - I want to delete all array-members with a specific Id for the year 2010 if they also have another year in the array (same id, different year). So in this case I would like to delete the [0] but not the other members.

Secondly - I want only to keep the next newest year after 2010 in this case for Id 1 the year 2009, meaning I want to delete [2] as well. (the years come as strings which is why I'm converting them into ints for the comparision in the code below)

Below is my code with for loops that work that I need expert Lambda help with to avoid the loops:

var x = Member.Length;

for (int i = 0; i < x; i++)
{
    var y = Member[i].id;
    for (int j = i; j < x; j++)
    {
        var z = Member[j].id;
        if (i != j)
        {
            if (y == z)
            {
                if (Member[i].year == "2010") 
                {
                    Member = Member.Where(w => w != Member[i]).ToArray();
                    i--;
                    j--;
                    x--;
                    break;
                }

                var tempI = Convert.ToInt32(Member[i].year);

                var tempJ = Convert.ToInt32(Member[j].year);

                if (tempI > tempJ)
                {
                    Member = Member.Where(w => w != Member[j]).ToArray();
                    i--;
                    j--;
                    x--;
                    break;
                }
            }
        }
    }
}
7
  • 4
    "Below is my code with for loops that work that I need expert Lambda help with to avoid the loops" Why do you think Linq will do this any different or even better? Usually all it does it to hide the complexity away, which is a bad thing. You shouldn´t overcomplicate your code using code you don´t understand. Instead strife for easy to understand code that works. Commented Nov 7, 2017 at 15:59
  • To hit up on @HimBromBeere, use what you know. If what you have works, then stick with it until you feel comfortable with something else. Odds are good the something else only cleans up the appearance (i.e. less lines of code) but does little to nothing to simplify it. Commented Nov 7, 2017 at 16:12
  • 1
    @gilliduck "Odds are good the something else only cleans up the appearance..." Well, uh, yeah. That's how you make your code easier to read, especially for others who didn't actually write it. It's never too soon to learn to write clean code, whether that be LINQ or native control flow. Commented Nov 7, 2017 at 16:19
  • 3
    @KennethK. short code != clean code. If you don't know what a portion does, then being verbose and extra wordy may be a huge benefit. I've got a (former) coworker who loved to be clever and write short code that was impossible to figure out. I'd have preferred long wordy loops than his clever "clean" code. Commented Nov 7, 2017 at 16:21
  • I want only to keep the next newest year after 2010 Could you elaborate on this? 2009 is before 2010 did you mean the closest or highest? Commented Nov 7, 2017 at 16:42

3 Answers 3

1

I agree that the requirement doesn't make a lot of sense but this is how I interpreted

var Member = new[]
           {
               new { id = 1, year = "2010" },

               new { id = 2, year = "2010" } ,

               new { id = 1, year = "2008" } ,

               new { id = 1, year = "2009" }  
           };

           var results = from item in Member.Select(x => new { x.id, Year = Convert.ToInt32(x.year), item = x })
                         group item by item.id into sameItems
                         let order = sameItems.OrderByDescending(x => x.Year)
                         let first = order.ElementAtOrDefault(0)
                         let second = order.ElementAtOrDefault(1)
                         select first.Year == 2010 && second != null ? second.item : first.item;

            foreach (var item in results)
            {
                System.Console.WriteLine($"id:{item.id},year:{item.year}");
            }        
Sign up to request clarification or add additional context in comments.

Comments

0

I tend to avoid using LINQ to change the underlying collection I'm querying. The code below will select up to two of most recent entries for each member.

var result = new List<MemberClass>();
var groups = Member.OrderBy(m => m.Id).ThenByDescending(m => m.Year).GroupBy(m => m.Id).ToList();
groups.ForEach(c => result.AddRange(c.Take(2)));

Use result instead of the original array.

I don't know if performance is a consideration for you. The code above may become slow as your collection grows.

Comments

0

Your description and requirements are incompatible, but here's one interpretation:

public class Member
{
    public int Id { get; set; }
    public string Year { get; set; }
}

var items = (new List<Member>() {
    new Member() { Id=1, Year="2010" },
    new Member() { Id=2, Year="2010" },
    new Member() { Id=1, Year="2008" },
    new Member() { Id=1, Year="2009" }
}).ToArray();

// Group everythnig by year, then only keep the highest id
var firstFiltered = items
    .GroupBy(
        x => x.Year,
        x => x.Id,
        (year, ids) => new Member()
                        {
                            Id = ids.Last(),
                            Year = year
                        });

var secondFiltered = firstFiltered
    // Only keep years before 2010
    .Where(x => String.Compare(x.Year, "2010") == -1)
    // Then order by Id then Year
    .OrderBy(x => x.Id)
    .ThenBy(x => x.Year)
    // And only keep the last/most recent year
    .GroupBy(
        x => x.Id,
        x => x.Year, 
        (id, years) => new Member() 
                        {
                            Id = id,
                            Year = years.Last()
                        });

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.