C# 使用 LINQ 将项目移动到列表顶部

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1668451/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-06 19:50:55  来源:igfitidea点击:

Use LINQ to move item to top of list

c#linqsorting

提问by qui

Is there a way to move an item of say id=10 as the first item in a list using LINQ?

有没有办法使用 LINQ 将 id=10 的项目作为列表中的第一项移动?

Item A - id =5
Item B - id = 10
Item C - id =12
Item D - id =1

In this case how can I elegantly move Item C to the top of my List<T>collection?

在这种情况下,我如何优雅地将项目 C 移动到我的List<T>收藏的顶部?

This is the best I have right now:

这是我现在最好的:

var allCountries = repository.GetCountries();
var topitem = allCountries.Single(x => x.id == 592);  
var finalList = new List<Country>();
finalList.Add(topitem);
finalList = finalList.Concat(allCountries.Where(x=> x.id != 592)).ToList();

采纳答案by JaredPar

LINQ is strong in querying collections, creating projections over existing queries or generating new queries based on existing collections. It is not meant as a tool to re-order existing collections inline. For that type of operation it's best to use the type at hande.

LINQ 在查询集合、在现有查询上创建投影或基于现有集合生成新查询方面非常强大。它并不意味着作为内联重新排序现有集合的工具。对于这种类型的操作,最好使用手头的类型。

Assuming you have a type with a similar definition as below

假设您有一个具有类似定义的类型,如下所示

class Item {
  public int Id { get; set; }
  ..
}

Then try the following

然后尝试以下操作

List<Item> list = GetTheList();
var index = list.FindIndex(x => x.Id == 12);
var item = list[index];
list[index] = list[0];
list[0] = item;

回答by Grizzly

Linq generallyworks on Enumerables, so it doesn't now that the underlying type is a collection. So for moving the item on top of the list I would suggest using something like (if you need to preserve the order)

Linq 通常在 Enumerables 上工作,所以现在它不是底层类型是一个集合。因此,为了将项目移到列表顶部,我建议使用类似的东西(如果您需要保留顺序)

var idx = myList.FindIndex(x => x.id == 592);
var item = myList[idx];
myList.RemoveAt(idx);
myList.Insert(0, item);

If your function returns only an IEnumerable, you can use the ToList()method to convert it to a List first

如果您的函数只返回一个 IEnumerable,您可以先使用该ToList()方法将其转换为 List

If you don't preserve the order you can simply swap the values at position 0 and position idx

如果您不保留顺序,您可以简单地交换位置 0 和位置 idx 处的值

回答by Jon Skeet

What do you want to order by, other than the known top item? If you don't care, you can do this:

除了已知的顶级商品之外,您还想订购什么?如果你不在乎,你可以这样做:

var query = allCountries.OrderBy(x => x.id != 592).ToList();

Basically, "false" comes before "true"...

基本上,“假”在“真”之前......

Admittedly I don't know what this does in LINQ to SQL etc. You may need to stop it from doing the ordering in the database:

不可否认,我不知道这在 LINQ to SQL 等中有什么作用。您可能需要阻止它在数据库中进行排序:

var query = allCountries.AsEnumerable()
                        .OrderBy(x => x.id != 592)
                        .ToList();

回答by configurator

Here is an extension method you might want to use. It moves the element(s) that match the given predicate to the top, preserving order.

这是您可能想要使用的扩展方法。它将与给定谓词匹配的元素移动到顶部,并保持顺序。

public static IEnumerable<T> MoveToTop(IEnumerable<T> list, Func<T, bool> func) {
    return list.Where(func)
               .Concat(list.Where(item => !func(item)));
}

In terms of complexity, I think it would make two passes on the collection, making it O(n), like the Insert/Remove version, but better than Jon Skeet's OrderBy suggestion.

就复杂性而言,我认为它会对集合进行两次传递,使其成为 O(n),就像插入/删除版本一样,但比 Jon Skeet 的 OrderBy 建议更好。

回答by Grozz

public static IEnumerable<T> ServeFirst<T>(this IEnumerable<T> source, 
    Predicate<T> p)
{
    var list = new List<T>();

    foreach (var s in source)
    {
        if (p(s))
            yield return s;
        else
            list.Add(s);
    }

    foreach (var s in list)
        yield return s;
}

回答by Adeola Ojo Gabriel

Its interesting the number of approaches you find when trying to solve a problem.

您在尝试解决问题时发现的方法数量很有趣。

var service = AutogateProcessorService.GetInstance();
var allConfigs = service.GetAll();
allConfigs = allConfigs.OrderBy(c => c.ThreadDescription).ToList();
var systemQueue = allConfigs.First(c => c.AcquirerId == 0);
allConfigs.Remove(systemQueue);
allConfigs.Insert(0, systemQueue);

回答by Gaotter

I know this a old question but I did it like this

我知道这是一个老问题,但我是这样做的

class Program
{
    static void Main(string[] args)
    {
        var numbers = new int[] { 5, 10, 12, 1 };

        var ordered = numbers.OrderBy(num => num != 10 ? num : -1);

        foreach (var num in ordered)
        {
            Console.WriteLine("number is {0}", num);
        }

        Console.ReadLine();
    }
}

this prints:

这打印:

number is 10
number is 1
number is 5
number is 12

数字是 10
数字是 1
数字是 5
数字是 12

回答by Filip

You can "group by" in two groups with Boolean key, and then sort them

您可以使用布尔键将两组“分组依据”,然后对它们进行排序

var finalList= allCountries
                .GroupBy(x => x.id != 592)
                .OrderBy(g => g.Key)
                .SelectMany(g => g.OrderBy(x=> x.id ));

回答by Nick Gillum

var allCountries = repository.GetCountries();
allCountries.OrderByDescending(o => o.id == 12).ThenBy(o => o.id) 

This will insert the object with id=12 at the top of the list and rotate the rest down, preserving the order.

这将在列表顶部插入 id=12 的对象并将其余对象向下旋转,保留顺序。

回答by Slai

To also check if the item was found without Exception, something like:

还要检查是否在没有异常的情况下找到了该项目,例如:

var allCountries = repository.GetCountries();
var lookup = allCountries.ToLookup(x => x.id == 592);  
var finalList = lookup[true].Concat(lookup[false]).ToList();
if ( lookup[true].Count() != 1 ) YouAreInTrouble();