2

I am trying to sort a custom list based on a string array, but I am failing miserably e.g. its not sorting the list at all,

Public class CrateOrder
{
   public int Id { get; set; }
   public string Name { get; set; }
   public Stream OrderStream { get; set; }
}

string[] selectedFruits = {"Apple", "Mango"};  // in real get from web services
var selectedFruitsList = selectedFruits.ToList();

List<CrateOrder> cFruit = GetCrateOrderFromWebServices();

var sorted = cFruit.OrderBy(s => selectedFruitsList.IndexOf(s.Name)).ToList();

It's not sorting the list properly, I want CrateOrder list item to be ordered based on selectedFruits...

10
  • 3
    I still don't understand how you are trying to sort your cFruit with your selectedFruits. An input and expected output for cFruit would help. Commented Feb 12, 2015 at 14:18
  • 1
    This looks fine to me - maybe I'm just missing the same thing, but are you sure your cFruit list items actually have Name properties that match your selectedFruits? Commented Feb 12, 2015 at 14:20
  • 1
    That's not a duplicate, there's something else going on here. Commented Feb 12, 2015 at 14:21
  • 6
    I suspect this is a case-sensitivity issue, IndexOf will do a case-sensitive search by default, unless specifying a different rule. Commented Feb 12, 2015 at 14:22
  • 2
    works for me ... dotnetfiddle.net/H1dt6p Commented Feb 12, 2015 at 14:22

3 Answers 3

2

If the Name property of your fruit does not match your ordering list exactly, IndexOf will always return -1. To get around this specify a case-insensitive StringComparison, but that is not available as an overload to IndexOf so you have to use a slightly more complex method:

var sorted = cFruit.OrderBy(
                     s => selectedFruitsList.FindIndex(
                            x => x.Equals(s.Name, StringComparison.OrdinalIgnoreCase)) )
                  .ToList();
Sign up to request clarification or add additional context in comments.

4 Comments

it worked with some adjustments, e.g. OrderByDescending and converting s.Name tolower, i know it shouldn't matter but thats how it worked, thanks
The StringComparison.OrdinalIgnoreCase was specifically to not have to do any case conversion.
I know, but for some reason, it wasn't working for me, I will look into it later, too occupied at this time :(
Here you go: rextester.com/ZOIS35246 - works absolutely fine with no need to change the case of anything (Note the Names have some lowercase starting letters)
2

You are almost there. The code orders the fruit from selectedFruitsList after all other items, because OrderBy order is ascending, and they are the only ones for which a non-negative number is returned.

To fix this, reverse selectedFruits, and negate the result of IndexOf, like this:

string[] selectedFruits = {"Mango", "Apple"};
...
var sorted = cFruit.OrderBy(s => -selectedFruitsList.IndexOf(s.Name)).ToList();

Alternatively, you could expand the code to deal with negative indexes explicitly:

string[] selectedFruits = {"Apple", "Mango"};
...
var sorted = cFruit.OrderBy(s => {
    int index = selectedFruitsList.IndexOf(s.Name);
    return index < 0 ? int.MaxValue : index;
}).ToList();

Comments

1

I wasn't aware if its case sensitive, can i add ignore culture to it

No - Array.IndexOf does not have parameters that let you customize the equality comparison.

Just change all of your selectedfruits and the search value to lower case:

string[] selectedFruits = {"Apple", "Mango"};  // in real get from web services
var selectedFruitsList = selectedFruits.Select(s => s.ToUpperInvariant()).ToList();

List<CrateOrder> cFruit = GetCrateOrderFromWebServices();

var sorted = cFruit.OrderBy(s => selectedFruitsList.IndexOf(s.Name.ToUpperInvariant())).ToList;

2 Comments

You should at very least be using ToLowerInvariant, but the recommendation is "Use the String.ToUpperInvariant method instead of the String.ToLowerInvariant method when you normalize strings for comparison"
@Jamiec fair enough - modified.

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.