1

I have read this question about retaining order in a list, but I didn't see anything about using the .Contains() method, hence why I'm asking this questions.

I have created a wrapper class which can contain different objects, like below:

public class RecommenderItem
{
    public Guid Id { get; set; }
    public object Entity { get; set; }
}

I have a method which orders a list, regardless of the type of object. Before I call the method which orders this list, I retrieve the objects from my database and map them to RecommenderItem. After this list is ordered, I want to return these items as their original type.

I have succesfully done this, but for the sake of readability, I would like to use LINQ in my entire method. Currently, I'm setting up my output list like this:

var filteredOnContent = ContentBasedFilter.FilterBasedOnContent(ratedItems, itemsNotReviewed); //This is the function which orders the list. Both ratedItems and itemsNotReviewed are lists of RecommenderItems
var restaurantObjects = (from S1 in filteredOnContent
                         from S2 in restaurantsCloseToUser
                         where S1.Id == S2.Id
                         select S2).ToList();

In this example is restaurantsCloseToUser the list that has been retrieved from the database.

I have tried the following, but it doesn't retain the order the filtered list has. This is very important, since the list is a top 10 of recommendations.

var test = restaurantsCloseToUser.Where(x => contentBasedFiltered.Select(r => r.Id).Contains(x.Id)).ToList();

Is there a way I can use LINQ and still retain the order of the filtered list?

Please let me know if I need to provide more information!

Community
  • 1
  • 1
  • `test` is in the same order as unfiltered `restaurantsCloseToUser`. Do you need the order of `contentBasedFiltered` instead? – Sergey Kalinichenko Jan 02 '17 at 10:34
  • What's the query for `filteredOnContent`? Is the query ordered? I don't see a reason why it order should change since you're just adding another filter... – Jeff Mercado Jan 02 '17 at 10:36
  • 1
    The only thing that could "destroy" the order is `toDictionary` and `toLookup` or redefining the "order by". if you want the order of one list use it as a "base" and select the element that is in the other one. the list.select ordre will remain the same – Drag and Drop Jan 02 '17 at 10:39
  • @PierreLebon thank you for that! My knowledge of LINQ is still very limited, so I'll definitely keep that in mind next time –  Jan 02 '17 at 11:03
  • @dasblinkenlight yes, I needed the order of `contentBasedFiltered`. I should have specified that, sorry! –  Jan 02 '17 at 11:04

1 Answers1

3

If I understand correctly, contentBasedFiltered is the ordered list and you want the original items from restaurantsCloseToUser but in the order they have in contentBasedFiltered. So I'd try the following:

var test = contentBasedFiltered.Select(x => restaurantsCloseToUser.FirstOrDefault(r => r.Id == x.Id)).ToList();

This returns a list in order of contentBasedFiltered but with the items from restaurantsCloseToUser.

René Vogt
  • 43,056
  • 14
  • 77
  • 99
  • @dasblinkenlight I agree that my answer lacks some error handling, but the correct way depends too much on OP's requirements. As the two lists are described by OP, there should be no not-matching id, so I can't decide what to do if there are. Even `Single()` could be appropriate if throwing in that special case would be the safest thing to do. – René Vogt Jan 02 '17 at 10:47
  • The items in the `contentBasedFiltered` list *always* exist in the `restaurantsCloseToUser` list, so this works perfectly, thank you! (Sorry if the question seemed confusing, should have specified I wanted to keep the order from the `contentBasedFiltered` list.) –  Jan 02 '17 at 11:02