Grupowanie według zakresu

0

Mam listę stringów i chcę ją pogrupować tak, że w jednej grupie tekst będzie zaczynał się od cyfry, w drugiej od litery z zakresu od a do g, potem h - m itd. Jedyne co wymyśliłem to tak jak poniżej, ale może da się to ogarnąć w GroupBy albo w Linq?

public class StringRangeGrouping
{
    public List<string> inputElements = new List<string>()
    {
        "ć_suffix",
        "C_suffix",
        "q_suffix",
        "w_suffix",
        "ę_suffix",
        "r_suffix",
        "t_suffix",
        "5_suffix",
        "u_suffix",
        "0_suffix",
        "o_suffix",
        "z_suffix",
        "x_suffix",
        "c_suffix",
        "v_suffix",
        "l_suffix",
        "b_suffix",
        "n_suffix"
    };

    List<Group> groups;

    public List<Group> GroupElements()
    {
        groups = new List<Group>();

        for (int i = 0; i < inputElements.Count; i++)
        {
            char firstLowerCaseChar = Char.ToLower(inputElements[i][0]);

            AddElementToGroup(GetGroupKey(firstLowerCaseChar), inputElements[i]);
        }

        return groups;
    }

    void AddElementToGroup(string groupKey, string element)
    {
        if (!groups.Exists(x => x.Key == groupKey))
        {
            groups.Add(new Group() { Key = groupKey });
        }

        groups.First(x => x.Key == groupKey).Elements.Add(element);
    }

    string GetGroupKey(char c)
    {
        if (c >= '0' && c <= '9')
        {
            return "0 - 9";
        }

        if (new char[] { 'a', 'ą', 'b', 'c', 'ć', 'd', 'e', 'ę', 'f', 'g' }.Contains(c))
        {
            return "a - g";
        }

        if (new char[] { 'h', 'i', 'j', 'k', 'l', 'm' }.Contains(c))
        {
            return "h - m";
        }

        //itd...

        return "Inne";
    }
}

public class Group
{
    public string Key { get; set; }
    public List<string> Elements { get; set; } = new List<string>();
}
2

No tak najprościej, to przecież wystarczyłoby Ci:

var result1 = inputElements.GroupBy(x => GetGroupKey(char.ToLowerInvariant(x[0])));

i cała reszta niepotrzebna.

Jeśli chcesz coś mniej hardcodowanego i bez tylu ifów, to sugeruję własne extension:

internal static class StringExtensions
{
    public static IEnumerable<IGrouping<string, string>> GroupByFirstCharacterRange(this IEnumerable<string> enumberable, IEnumerable<string> ranges, string defaultKey = "Inne")
    {
        string GetGroupKey(string item)
        {
            var c = item.ToLowerInvariant().Normalize(NormalizationForm.FormD).First();
            var result = ranges.SingleOrDefault(r => c >= r.First() && c <= r.Last());
            return result ?? defaultKey;
        }

        return enumberable.GroupBy(GetGroupKey);
    }
}

Użycie:

var result = inputElements.GroupByFirstCharacterRange(new string[] { "0 - 9", "a - g", "h - m" });

1 użytkowników online, w tym zalogowanych: 0, gości: 1