Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/263.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/linq/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 针对特定值的Linq OrderBy_C#_Linq_Linq To Objects - Fatal编程技术网

C# 针对特定值的Linq OrderBy

C# 针对特定值的Linq OrderBy,c#,linq,linq-to-objects,C#,Linq,Linq To Objects,在Linq中有没有一种方法可以在不知道值的顺序的情况下对一组值(本例中为字符串)执行OrderBy 考虑以下数据: A B A C B C D E 这些变量: 字符串firstPref、secondPref、thirdPref 当值设置为这样时: firstPref = 'A'; secondPref = 'B'; thirdPref = 'C'; 是否可以按如下方式对数据进行排序: A A B B C C D E 是的,您必须实现自己的IComparer,然后将其作为LINQ的Order

在Linq中有没有一种方法可以在不知道值的顺序的情况下对一组值(本例中为字符串)执行OrderBy

考虑以下数据:

A
B
A
C
B
C
D
E
这些变量:

字符串firstPref、secondPref、thirdPref

当值设置为这样时:

firstPref = 'A';
secondPref = 'B';
thirdPref = 'C';
是否可以按如下方式对数据进行排序:

A
A
B
B
C
C
D
E

是的,您必须实现自己的
IComparer
,然后将其作为LINQ的OrderBy方法的第二个参数传入

可以在此处找到一个示例:

如果将您的首选项放入列表中,可能会更容易

List<String> data = new List<String> { "A","B","A","C","B","C","D","E" };
List<String> preferences = new List<String> { "A","B","C" };

IEnumerable<String> orderedData = data.OrderBy(
   item => preferences.IndexOf(item));
如果您关注
首选项
数据
,解决方案会变得更好

IEnumerable<String> orderedData = data.OrderBy(
   item => preferences.Concat(data).ToList().IndexOf(item));
IEnumerable orderedData=data.OrderBy(
item=>preferences.Concat(data.ToList().IndexOf(item));

我不喜欢那里的
Concat()
ToList()
。但目前我还没有很好的解决办法。我正在寻找一个很好的技巧,将第一个示例的
-1
变成一个大数字。

Danbrucs解决方案更优雅,但这里有一个使用自定义IComparer的解决方案。如果您需要更高级的排序条件,这可能很有用

    string[] svals = new string[] {"A", "B", "A", "C", "B", "C", "D", "E"};
    List<string> list = svals.OrderBy(a => a, new CustomComparer()).ToList();

    private class CustomComparer : IComparer<string>
    {
        private string firstPref = "A";
        private string secondPref = "B";
        private string thirdPref = "C";
        public int Compare(string x, string y)
        {
            // first pref 
            if (y == firstPref && x == firstPref)
                return 0;
            else if (x == firstPref && y != firstPref)
                return -1;
            else if (y == firstPref && x != firstPref)
                return 1;
            // second pref
            else if (y == secondPref && x == secondPref)
                return 0;
            else if (x == secondPref && y != secondPref)
                return -1;
            else if (y == secondPref && x != secondPref)
                return 1;
            // third pref
            else if (y == thirdPref && x == thirdPref)
                return 0;
            else if (x == thirdPref && y != thirdPref)
                return -1;
            else
                return string.Compare(x, y);
        }
    }
string[]svals=新字符串[]{“A”、“B”、“A”、“C”、“B”、“C”、“D”、“E”};
List List=svals.OrderBy(a=>a,new CustomComparer()).ToList();
私有类CustomComparer:IComparer
{
私有字符串firstPref=“A”;
私有字符串secondPref=“B”;
私有字符串thirdPref=“C”;
公共整数比较(字符串x、字符串y)
{
//第一优先
如果(y==firstPref&&x==firstPref)
返回0;
else if(x==firstPref&&y!=firstPref)
返回-1;
else如果(y==firstPref&&x!=firstPref)
返回1;
//第二优先
else if(y==secondPref&&x==secondPref)
返回0;
else if(x==secondPref&&y!=secondPref)
返回-1;
如果(y==secondPref&&x!=secondPref),则为else
返回1;
//第三优先
else如果(y==thirdPref&&x==thirdPref)
返回0;
else如果(x==thirdPref&&y!=thirdPref)
返回-1;
其他的
返回字符串。比较(x,y);
}
}

将首选值放入字典中。在字典中查找键是一个O(1)操作,而在列表中查找值是一个O(n)操作,因此它的伸缩性更好

为每个首选值创建一个排序字符串,以便将它们放在其他值之前。对于其他值,值本身将用作排序字符串,以便实际对它们进行排序。(使用任意高的值只会将它们未排序地放在列表的末尾)

列表数据=新列表{
“E”、“B”、“D”、“A”、“C”、“B”、“A”、“C”
};
var preferences=新字典{
{“A”,“01”},
{“B”,“02”},
{“C”,“03”}
};
字符串键;
IEnumerable orderedData=data.OrderBy(
item=>preferences.TryGetValue(item,out键)?键:item
);

除了@Daniel Brückner及其结尾定义的问题:

我不喜欢那里的Concat()和ToList()。但目前我还没有什么好办法。我正在寻找一个很好的技巧,将第一个>示例的-1变成一个大数字

我认为解决方案是使用语句lambda而不是表达式lambda

var data = new List<string> { "corge", "baz", "foo", "bar", "qux", "quux" };
var fixedOrder = new List<string> { "foo", "bar", "baz" };
data.OrderBy(d => {
                    var index = fixedOrder.IndexOf(d);
                    return index == -1 ? int.MaxValue : index; 
                  });
将所有答案(以及更多答案)组合到支持缓存的通用LINQ扩展中,该扩展可处理任何数据类型,可以不区分大小写,并允许与预排序和后排序链接:

public static class SortBySample
{
    public static BySampleSorter<TKey> Create<TKey>(IEnumerable<TKey> fixedOrder, IEqualityComparer<TKey> comparer = null)
    {
        return new BySampleSorter<TKey>(fixedOrder, comparer);
    }

    public static BySampleSorter<TKey> Create<TKey>(IEqualityComparer<TKey> comparer, params TKey[] fixedOrder)
    {
        return new BySampleSorter<TKey>(fixedOrder, comparer);
    }

    public static IOrderedEnumerable<TSource> OrderBySample<TSource, TKey>(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector, BySampleSorter<TKey> sample)
    {
        return sample.OrderBySample(source, keySelector);
    }

    public static IOrderedEnumerable<TSource> ThenBySample<TSource, TKey>(this IOrderedEnumerable<TSource> source, Func<TSource, TKey> keySelector, BySampleSorter<TKey> sample)
    {
        return sample.ThenBySample(source, keySelector);
    }
}

public class BySampleSorter<TKey>
{
    private readonly Dictionary<TKey, int> dict;

    public BySampleSorter(IEnumerable<TKey> fixedOrder, IEqualityComparer<TKey> comparer = null)
    {
        this.dict = fixedOrder
            .Select((key, index) => new KeyValuePair<TKey, int>(key, index))
            .ToDictionary(kv => kv.Key, kv => kv.Value, comparer ?? EqualityComparer<TKey>.Default);
    }

    public BySampleSorter(IEqualityComparer<TKey> comparer, params TKey[] fixedOrder)
        : this(fixedOrder, comparer)
    {
    }

    public IOrderedEnumerable<TSource> OrderBySample<TSource>(IEnumerable<TSource> source, Func<TSource, TKey> keySelector)
    {
        return source.OrderBy(item => this.GetOrderKey(keySelector(item)));
    }

    public IOrderedEnumerable<TSource> ThenBySample<TSource>(IOrderedEnumerable<TSource> source, Func<TSource, TKey> keySelector)
    {
        return source.CreateOrderedEnumerable(item => this.GetOrderKey(keySelector(item)), Comparer<int>.Default, false);
    }

    private int GetOrderKey(TKey key)
    {
        int index;
        return dict.TryGetValue(key, out index) ? index : int.MaxValue;
    }
}

对于大型列表而言,效率不高,但易于阅读:

public class FixedOrderComparer<T> : IComparer<T>
{
    private readonly T[] fixedOrderItems;

    public FixedOrderComparer(params T[] fixedOrderItems)
    {
        this.fixedOrderItems = fixedOrderItems;
    }

    public int Compare(T x, T y)
    {
        var xIndex = Array.IndexOf(fixedOrderItems, x);
        var yIndex = Array.IndexOf(fixedOrderItems, y);
        xIndex = xIndex == -1 ? int.MaxValue : xIndex;
        yIndex = yIndex == -1 ? int.MaxValue : yIndex;
        return xIndex.CompareTo(yIndex);
    }
}
公共类固定排序比较程序:IComparer
{
私有只读T[]固定顺序;
公共固定顺序比较程序(参数T[]固定顺序)
{
this.fixedOrderItems=fixedOrderItems;
}
公共整数比较(TX,TY)
{
var xIndex=Array.IndexOf(fixedOrderItems,x);
var yIndex=Array.IndexOf(fixedOrderItems,y);
xIndex=xIndex==-1?int.MaxValue:xIndex;
yIndex=yIndex==-1?int.MaxValue:yIndex;
返回xIndex.CompareTo(yIndex);
}
}
用法:

var orderedData = data.OrderBy(x => x, new FixedOrderComparer<string>("A", "B", "C"));
var orderedData=data.OrderBy(x=>x,新的固定顺序比较(“A”、“B”、“C”);

注意:
Array.IndexOf(..)
使用
EqualityComparer.Default
查找目标索引。

我使用这些。我喜欢IEnumerable重载来保持整洁,但是优先级映射版本在重复调用时应该有更好的性能

    public static IEnumerable<T> OrderByStaticList<T>(this IEnumerable<T> items, IReadOnlyDictionary<T, double> priorityMap)
    {
        return items.OrderBy(x => priorityMap.GetValueOrDefault(x, double.MaxValue));
    }

    public static IEnumerable<T> OrderByStaticList<T>(this IEnumerable<T> items, IEnumerable<T> preferenceOrder)
    {
        int priority = 0;
        var priorityMap = preferenceOrder.ToDictionary(x => x, x => (double) priority++);
        return OrderByStaticList(items, priorityMap);
    }




    [TestMethod]
    public void PriorityMap_DeterminesSort()
    {
        var map = new Dictionary<char, double>()
        {
            {'A', 1},
            {'B', 7},
            {'C', 3},
            {'D', 42},
            {'E', -1},
        };
        Assert.AreEqual("EACBD", new string("ABCDE".OrderByStaticList(map).ToArray()));
    }

    [TestMethod]
    public void PriorityMapMissingItem_SortsLast()
    {
        var map = new Dictionary<char, double>()
        {
            {'A', 1},
            {'B', 7},
            {'D', 42},
            {'E', -1},
        };
        Assert.AreEqual("EABDC", new string("ABCDE".OrderByStaticList(map).ToArray()));
    }

    [TestMethod]
    public void OrderedList_DeterminesSort()
    {
        Assert.AreEqual("EACBD", new string("ABCDE".OrderByStaticList("EACBD").ToArray()));
    }

    [TestMethod]
    public void OrderedListMissingItem_SortsLast()
    {
        Assert.AreEqual("EABDC", new string("ABCDE".OrderByStaticList("EABD").ToArray()));
    }
公共静态IEnumerable OrderByStaticList(此IEnumerable项,IReadOnlyDictionary priorityMap)
{
returnitems.OrderBy(x=>priorityMap.GetValueOrDefault(x,double.MaxValue));
}
公共静态IEnumerable OrderByStaticList(此IEnumerable items,IEnumerable preferenceOrder)
{
int优先级=0;
var priorityMap=preferenceOrder.ToDictionary(x=>x,x=>(双)优先级++);
return OrderByStaticList(项目,优先映射);
}
[测试方法]
public void PriorityMap_DeterminesSort()
{
var map=newdictionary()
{
{'A',1},
{'B',7},
{'C',3},
{'D',42},
{'E',-1},
};
AreEqual(“EACBD”,新字符串(“ABCDE.OrderByStaticList(map.ToArray()));
}
[测试方法]
公共无效优先许可许可项目(SortsLast)()
{
var map=newdictionary()
{
{'A',1},
{'B',7},
{'D',42},
{'E',-1},
};
AreEqual(“EABDC”,新字符串(“ABCDE.OrderByStaticList(map.ToArray()));
}
[测试方法]
public void OrderedList_DeterminesSort()
{
aresequal(“EACBD”),新字符串(“ABCDE”
var sample = SortBySample.Create(StringComparer.OrdinalIgnoreCase, "one", "two", "three", "four");
var unsorted = new[] {"seven", "six", "five", "four", "THREE", "tWo", "One", "zero"};
unsorted
    .OrderBySample(x => x, sample)
    .ThenBy(x => x)
    .Dump("sorted by sample then by content");
unsorted
    .OrderBy(x => x.Length)
    .ThenBySample(x => x, sample)
    .Dump("sorted by length then by sample");
public class FixedOrderComparer<T> : IComparer<T>
{
    private readonly T[] fixedOrderItems;

    public FixedOrderComparer(params T[] fixedOrderItems)
    {
        this.fixedOrderItems = fixedOrderItems;
    }

    public int Compare(T x, T y)
    {
        var xIndex = Array.IndexOf(fixedOrderItems, x);
        var yIndex = Array.IndexOf(fixedOrderItems, y);
        xIndex = xIndex == -1 ? int.MaxValue : xIndex;
        yIndex = yIndex == -1 ? int.MaxValue : yIndex;
        return xIndex.CompareTo(yIndex);
    }
}
var orderedData = data.OrderBy(x => x, new FixedOrderComparer<string>("A", "B", "C"));
    public static IEnumerable<T> OrderByStaticList<T>(this IEnumerable<T> items, IReadOnlyDictionary<T, double> priorityMap)
    {
        return items.OrderBy(x => priorityMap.GetValueOrDefault(x, double.MaxValue));
    }

    public static IEnumerable<T> OrderByStaticList<T>(this IEnumerable<T> items, IEnumerable<T> preferenceOrder)
    {
        int priority = 0;
        var priorityMap = preferenceOrder.ToDictionary(x => x, x => (double) priority++);
        return OrderByStaticList(items, priorityMap);
    }




    [TestMethod]
    public void PriorityMap_DeterminesSort()
    {
        var map = new Dictionary<char, double>()
        {
            {'A', 1},
            {'B', 7},
            {'C', 3},
            {'D', 42},
            {'E', -1},
        };
        Assert.AreEqual("EACBD", new string("ABCDE".OrderByStaticList(map).ToArray()));
    }

    [TestMethod]
    public void PriorityMapMissingItem_SortsLast()
    {
        var map = new Dictionary<char, double>()
        {
            {'A', 1},
            {'B', 7},
            {'D', 42},
            {'E', -1},
        };
        Assert.AreEqual("EABDC", new string("ABCDE".OrderByStaticList(map).ToArray()));
    }

    [TestMethod]
    public void OrderedList_DeterminesSort()
    {
        Assert.AreEqual("EACBD", new string("ABCDE".OrderByStaticList("EACBD").ToArray()));
    }

    [TestMethod]
    public void OrderedListMissingItem_SortsLast()
    {
        Assert.AreEqual("EABDC", new string("ABCDE".OrderByStaticList("EABD").ToArray()));
    }