C#对字符串列表对字典进行排序?

时间:2018-12-07 20:43:49

标签: c# .net

我有以下列表(忽略LST ==>部分):

LST ==>Username
LST ==>Password
LST ==>SampleRequestValue
LST ==>SampleComplexRequest
LST ==>SampleComplexRequest.SampleTestBValue
LST ==>SampleComplexRequest.SampleTestAValue

和字典中的以下密钥列表(忽略DICT ==>部分):

DICT ==>Password
DICT ==>Username
DICT ==>SampleRequestValue
DICT ==>SampleComplexRequest.SampleTestAValue
DICT ==>SampleComplexRequest.SampleTestBValue

我希望字典按列表的顺序排序(即,密码前的用户名)。

在sorta / kinda /的SO上看到了一些示例,这并不是真正的示例...但实际上不是类似的情况。还希望它尽可能快,而不要强行使用它。

LST可能比DICT包含更多项目。我只关心排序DICT。 DICT在LST中将始终具有匹配的条目。我只想按LST顺序订购DICT。

4 个答案:

答案 0 :(得分:1)

另一种方法是编写一个小的自定义比较器类,该类使用列表来确定比较值:

public class ListComparer : IComparer<string>
{
    public List<string> ComparisonList { get; set; }

    public ListComparer(List<string> comparisonList)
    {
        ComparisonList = comparisonList;
    }

    public int Compare(string x, string y)
    {
        if (ComparisonList == null || !ComparisonList.Contains(x))
            return 1;

        if (ComparisonList.Contains(y))
            return ComparisonList.IndexOf(x).CompareTo(ComparisonList.IndexOf(y));

        return -1;
    }
}

然后,您可以将其传递给SortedDictionary的构造函数,然后在每次将项添加到字典时都将使用它。这样,您不必每次添加新值时都在字典上调用OrderBy(这也会带来每次创建一个新字典的负面影响)。

以下代码示例可能会有所帮助。请注意,我们先添加“密码”,然后添加“用户名”,但是当我们输出项目时,它们按预期顺序排列:

static void Main()
{
    var comparisonList = new List<string>
    {
        "Username",
        "Password",
        "SampleRequestValue",
        "SampleComplexRequest",
        "SampleComplexRequest.SampleTestBValue",
        "SampleComplexRequest.SampleTestAValue",
    };

    // Add items in an "unorderd" order
    var items = new SortedDictionary<string, string>(new ListComparer(comparisonList))
    {
        {"Password", "LetMeIn"},
        {"Username", "JohnDoe"}
    };

    foreach (var item in items)
    {
        Console.WriteLine($"{item.Key} = {item.Value}");
    }

    GetKeyFromUser("\nDone! Press any key to exit...");
}

输出

enter image description here


我刚刚看到您无法控制初始词典,但愿意创建一个新词典。在这种情况下,您只需使用带有字典和比较器的重载构造函数,它将自动在列表中排序:

 var sortedItems = new SortedDictionary<string, string>(
     originalDictionary, new ListComparer(comparisonList));

答案 1 :(得分:1)

使用LINQ非常简单。

首先,设置一个Dictionary<string,int>来代表所需的排序顺序:

var orderList = new[] { "Username", "Password", "SampleRequestValue", "SampleComplexRequest", "SampleComplexRequest.SampleTestBValue", "SampleComplexRequest.SampleTestAValue" }
                .ToList();

var sortOrder = orderList
                    .Select((s, p) => new { s, p })
                    .ToDictionary(sp => sp.s, sp => sp.p);

然后您可以将DictionaryEntry中的OrderedDictionary排序:

var ans = src.Cast<DictionaryEntry>().OrderBy(de => sortOrder[(string)de.Key]);

如果您希望答案是OrderedDictionary,则可以使用扩展方法转换回去:

public static class IEnumerableExt {
    public static OrderedDictionary ToOrderedDictionary<TKey,TValue,TObj>(this IEnumerable<TObj> src, Func<TObj,TKey> keyFn, Func<TObj, TValue> valueFn) {
        var ans = new OrderedDictionary();
        foreach (var s in src)
            ans.Add(keyFn(s), valueFn(s));
        return ans;
    }    
}

现在只需使用扩展方法:

var odans = ans.ToOrderedDictionary(s => s.Key, s => s.Value);

答案 2 :(得分:0)

只需使用OrderBy方法:

var SortedDic = dic.OrderBy(o => lst.IndexOf(o.Key));

答案 3 :(得分:0)

以下三种扩展方法将以不同的方式完成您想要的事情。

它们的用法如下(KeySortItemsValueSortItems是不同的List<string>列表:

DictionaryItems.ListOrderByKey(KeySortItems)
DictionaryItems.ListOrderByValue(ValueSortItems)
DictionaryItems.ListOrderBy(KeySortItems, (kv, value) => kv.Key.Equals(value))

public static IEnumerable<KeyValuePair<TKey, TValue>> ListOrderByKey<TKey, TValue>(this IDictionary<TKey, TValue> dictionary, List<TValue> list)
{
    foreach (var value in list)
        foreach (var kv in dictionary)
            if (kv.Key.Equals(value))
            {
                yield return kv;
                break;
            }
}

public static IEnumerable<KeyValuePair<TKey, TValue>> ListOrderByValue<TKey, TValue>(this IDictionary<TKey, TValue> dictionary, List<TValue> list)
{
    foreach (var value in list)
        foreach (var kv in dictionary)
            if (kv.Value.Equals(value))
                yield return kv;
}

public static IEnumerable<KeyValuePair<TKey, TValue>> ListOrderBy<TKey, TValue>(this IDictionary<TKey, TValue> dictionary, List<TValue> list, Func<KeyValuePair<TKey, TValue>, TValue, bool> func)
{
    foreach (var value in list)
        foreach (var kv in dictionary)
            if (func.Invoke(kv, value))
                yield return kv;
}

复制并粘贴控制台应用。

using System;
using System.Collections.Generic;

public class Program
{
    public static List<string> KeySortItems { get; set; } = new List<string>()
    {
        "Username",
        "Password",
        "Item not in Dictionary",
        "SampleRequestValue",
        "SampleComplexRequest"
    };

    public static List<string> ValueSortItems { get; set; } = new List<string>()
    {
        "Mathew",
        "1234",
        "Item not in Dictionary",
        "Sample Request",
        "Something Complex"
    };

    public static Dictionary<string, string> DictionaryItems { get; set; } = new Dictionary<string, string>()
    {
        ["Password"] = "1234",
        ["Username"] = "Mathew",
        ["SampleComplexRequest"] = "Something Complex",
        ["SampleRequestValue"] = "Sample Request"
    };


    public static void Main()
    {
        Console.WriteLine("Original Dictionary");
        foreach (var kv in DictionaryItems)
        {
            Console.WriteLine($"{kv.Key} : { kv.Value}");
        }


        Console.WriteLine("\nSorted by Key");
        foreach (var kv in DictionaryItems.ListOrderByKey(KeySortItems))
        {
            Console.WriteLine($"{kv.Key} : { kv.Value}");
        }

        Console.WriteLine("\nSorted by Value");
        foreach (var kv in DictionaryItems.ListOrderByValue(ValueSortItems))
        {
            Console.WriteLine($"{kv.Key} : { kv.Value}");
        }

        Console.WriteLine("\nSorted by Keys via func");
        foreach (var kv in DictionaryItems.ListOrderBy(KeySortItems, (kv, value) => kv.Key.Equals(value)))
        {
            Console.WriteLine($"{kv.Key} : { kv.Value}");
        }

        Console.ReadKey();
    }
}

public static class Extensions
{
    public static IEnumerable<KeyValuePair<TKey, TValue>> ListOrderByKey<TKey, TValue>(this IDictionary<TKey, TValue> dictionary, List<TValue> list)
    {
        foreach (var value in list)
            foreach (var kv in dictionary)
                if (kv.Key.Equals(value))
                    yield return kv;
    }

    public static IEnumerable<KeyValuePair<TKey, TValue>> ListOrderByValue<TKey, TValue>(this IDictionary<TKey, TValue> dictionary, List<TValue> list)
    {
        foreach (var value in list)
            foreach (var kv in dictionary)
                if (kv.Value.Equals(value))
                    yield return kv;
    }

    public static IEnumerable<KeyValuePair<TKey, TValue>> ListOrderBy<TKey, TValue>(this IDictionary<TKey, TValue> dictionary, List<TValue> list, Func<KeyValuePair<TKey, TValue>, TValue, bool> func)
    {
        foreach (var value in list)
            foreach (var kv in dictionary)
                if (func.Invoke(kv, value))
                    yield return kv;
    }
}

//OUTPUT
//Original Dictionary
//Password : 1234
//Username : Mathew
//SampleComplexRequest : Something Complex
//SampleRequestValue : Sample Request

//Sorted by Key
//Username : Mathew
//Password : 1234
//SampleRequestValue : Sample Request
//SampleComplexRequest : Something Complex

//Sorted by Value
//Username : Mathew
//Password : 1234
//SampleRequestValue : Sample Request
//SampleComplexRequest : Something Complex

//Sorted by Keys via func
//Username : Mathew
//Password : 1234
//SampleRequestValue : Sample Request
//SampleComplexRequest : Something Complex