简体   繁体   中英

Sorting strings in C#

I have a delimited string that I need sorted. First I need to check if 'Francais' is in the string, if so, it goes first, then 'Anglais' is next, if it exists. After that, everything else is alphabetical. Can anyone help me? Here's what I have so far, without the sorting

private string SortFrench(string langs)
    {
       string _frenchLangs = String.Empty;
       string retval = String.Empty;

        _frenchLangs = string.Join(" ; ",langs.Split(';').Select(s => s.Trim()).ToArray());

        if (_frenchLangs.Contains("Francais"))
            retval += "Francais";

        if (_frenchLangs.Contains("Anglais"))
        {
            if (retval.Length > 0)
                retval += " ; ";

            retval += "Anglais";
        }

        //sort the rest

        return retval;
    }

Someone liked my comment, so figured I'd go ahead and convert that into your code:

private string SortFrench(string langs)
{
    var sorted          = langs.Split(';')
        .Select(s => s.Trim())
        .OrderByDescending( s => s == "Francais" )
        .ThenByDescending( s => s == "Anglais" )
        .ThenBy ( s => s )
        .ToArray();

    return string.Join(" ; ",sorted);
}

My syntax may be off slightly as I've been in the Unix world for awhile now and haven't used much LINQ lately, but hope it helps.

You should use a custom comparer class

it will allow you to use the built in collection sorting functions, or the linq OrderBy using your own criteria

Here's what I came up with. You could change the .Sort() for a OrderBy(lang => lang) after the Select, but I find it's cleaner that way.

public string SortLanguages(string langs)
{
    List<string> languages = langs.Split(';').Select(s => s.Trim()).ToList();

    languages.Sort();
    PlaceAtFirstPositionIfExists(languages, "anglais");
    PlaceAtFirstPositionIfExists(languages, "francais");

    return string.Join(" ; ", languages);
}

private void PlaceAtFirstPositionIfExists(IList<string> languages, string language)
{
    if (languages.Contains(language))
    {
            languages.Remove(language);
            languages.Insert(0, language);
    }
}

Try this:

private string SortFrench(string langs)
{
    string _frenchLangs = String.Empty;

    List<string> languages = langs
        .Split(';')
        .Select(s => s.Trim())
        .OrderBy(s => s)
        .ToList();

    int insertAt = 0;

    if (languages.Contains("Francais"))
    {
        languages.Remove("Francais");
        languages.Insert(insertAt, "Francais");
        insertAt++;
    }

    if(languages.Contains("Anglais"))
    {
        languages.Remove("Anglais");
        languages.Insert(insertAt, "Anglais");
    }

    _frenchLangs = string.Join(" ; ", languages);

    return _frenchLangs;
}

All can be done in single line

private string SortFrench(string langs)
{
    return string.Join(" ; ", langs.Split(';').Select(s => s.Trim())
                    .OrderBy(x => x != "Francais")
                    .ThenBy(x => x != "Anglais")
                    .ThenBy(x=>x));
}

Sorting alphabetically is simple; adding .OrderBy(s => s) before that .ToArray() will do that. Sorting based on the presence of keywords is trickier.

The quick and dirty way is to split into three:

  • Strings containing "Francais": .Where(s => s.Contains("Francais")
  • Strings containing "Anglais": .Where(s => s.Contains("Anglais")
  • The rest: .Where(s => !francaisList.Contains(s) && !anglaisList.Contains(s))

Then you can sort each of these alphabetically, and concatenate them.

Alternatively, you can implement IComparer using the logic you described:

For strings A and B:

  • If A contains "Francais"
    • If B contains "Francais", order alphabetically
  • Else
    • If B contains "Francais", B goes first
    • Else
      • If A contains "Anglais"
        • If B contains "Anglais", order alphabetically
        • Else, A goes first
      • Else, order alphabetically

There may be room for logical re-arrangement to simplify that. With all that logic wrapped up in a class that implements IComparer , you can specify that class for use by .OrderBy() to have it order your query results based on your custom logic.

你也可以使用Array.Sort(yourStringArray)

This way you can set any list of words in front:

private static string SortFrench(string langs, string[] setStartList)
{
    string _frenchLangs = String.Empty;
    List<string> list = langs.Split(';').Select(s => s.Trim()).ToList();
    list.Sort();
    foreach (var item in setStartList){
    if (list.Contains(item))
    {
        list.Remove(setFirst);
    }
   }
    List<string> tempList = List<string>();
    tempList.AddRange(setStartList);
    tempList.AddRange(list);
    list = tempList;
    _frenchLangs = string.Join(" ; ", list);

    return _frenchLangs;
}

This code creates a list of the languages, sorts them using a custom comparer, and then puts the sorted list back together:

        const string langs = "foo;bar;Anglais;Francais;barby;fooby";
        var langsList = langs.Split(';').ToList();
        langsList.Sort((s1, s2) =>
            {
                if (s1 == s2)
                    return 0;
                if (s1 == "Francais")
                    return -1;
                if (s2 == "Francais")
                    return 1;
                if (s1 == "Anglais")
                    return -1;
                if (s2 == "Anglais")
                    return 1;
                return s1.CompareTo(s2);
            });
        var sortedList = string.Join(";", langsList);
        Console.WriteLine(sortedList);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM