3
var listOne = new string[] { "dog", "cat", "car", "apple"};
var listTwo = new string[] { "car", "apple"};

What I need is to order listOne by the order of items in listTwo (if present). So the new list would be in this order; "car", "apple", "dog", "cat"

I would like to do this in LINQ and have tried this;

var newList = from l1 in listOne
              join l2 in listTwo on l1 equals l2 in temp
              from nl temp.DefaultIfEmpty()
              select nl;

But it returns null so evidently my Linq-Fu is weak. Any advise is appreciated.

1
  • 1
    Can duplicates exist in listOne? If so, should they be preserved? Commented Mar 1, 2011 at 18:35

2 Answers 2

4

You need all the items from listTwo that are in listOne followed by the remaining items from listOne?

var results = listTwo.Intersect(listOne).Union(listOne);
foreach (string r in results)
{
    Console.WriteLine(r);
}
Sign up to request clarification or add additional context in comments.

7 Comments

Why do you need the second Except? It's a union; they won't appear twice.
I had changed to Concat for a minute, but you're right. Union without the Except is probably more elegant. listTwo.Intersect(listOne).Union(listOne);
@Lasse my original answer was a Union instead of a Concat. Mark is correct.
This could be further shortened to just listTwo.Union(listOne). Per MSDN: "This method excludes duplicates from the return set."
@Ahmad if listTwo contained "orange" but listOne did not, your solution would include it but mine would not. The way I read it, listTwo should only be used to order the items of listOne and therefore orange should not be included.
|
3

Well, let me rephrase your sorting requirements:

  1. First, all the items from the first list, that is also present in the second list, and return them in the order they appear in that second list, or: all the elements from the second list, if they appear in the first list
  2. Then, all the items from the first list, that is not in that second list, and return them in the order they appear in that first list

This code would do the trick:

void Main()
{
    var listOne = new string[] { "dog", "cat", "car", "apple"};
    var listTwo = new string[] { "car", "apple"};

    var elements1 =
        from element in listTwo
        where listOne.Contains(element)
        select element;
    var elements2 =
        from element in listOne
        where !listTwo.Contains(element)
        select element;

    elements1.Concat(elements2).Dump();
}

You can also rewrite it without the LINQ syntax to make it a bit shorter:

void Main()
{
    var listOne = new string[] { "dog", "cat", "car", "apple"};
    var listTwo = new string[] { "car", "apple"};

    var elements = listTwo.Where(e => listOne.Contains(e))
        .Concat(listOne.Where(e => !listTwo.Contains(e)));

    elements.Dump();
}

Output (through LINQPad):

car 
apple 
dog 
cat 

2 Comments

Good solution, BTW having listOne {"A","A","B","C"} and listTwo{"A","C"} IMO should yield {"A","A","C","B"} not {"A","C","B"} as in your code...don't know if OP needs this though ;)
Incidentally Intersect and Except are far more efficient than Where..Contains

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.