88 votes

Utiliser LINQ pour déplacer un élément en haut de la liste

Existe-t-il un moyen de déplacer un élément de disons id=10 comme premier élément d'une liste en utilisant LINQ ?

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

Dans ce cas, comment puis-je déplacer élégamment l'élément C vers le haut de ma page d'accueil ? List<T> collection ?

C'est le meilleur que j'ai pour le moment :

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();

0 votes

Voulez-vous échanger l'élément avec l'élément du haut ou faire tourner les éléments en poussant tous les éléments jusqu'à l'élément trouvé vers le bas.

0 votes

N'a pas finalList .insert(0, "neww stuff") ; travail

148voto

Jon Skeet Points 692016

Par quoi voulez-vous commander, à part l'article de tête connu ? Si vous ne vous en souciez pas, vous pouvez le faire :

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

Fondamentalement, "faux" vient avant "vrai"...

Il est vrai que je ne sais pas ce que cela fait dans LINQ to SQL, etc. Il se peut que vous deviez l'empêcher d'effectuer le classement dans la base de données :

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

1 votes

Son ne fonctionne pas comme prévu pour LINQ to SQL. Je viens de le tester.

6 votes

+1 Merci Jon. Je voulais ordonner par nom mais garder l'élément avec id=0 en haut, donc j'ai fait ceci : allCountries.OrderBy(x => x.id == 0 ? "00000" : x.Name).ToList() ; la performance n'est pas un problème parce que la liste est petite.

3 votes

Pour quelqu'un qui reverrait le code plus tard, il pourrait ne pas être évident que les valeurs booléennes sont ordonnées "faux, vrai". Je recommande les solutions plus verbeuses.

57voto

JaredPar Points 333733

LINQ est fort pour interroger des collections, créer des projections sur des requêtes existantes ou générer de nouvelles requêtes basées sur des collections existantes. Il ne s'agit pas d'un outil permettant de réorganiser des collections existantes en ligne. Pour ce type d'opération, il est préférable d'utiliser le type à portée de main.

Supposons que vous ayez un type avec une définition similaire à celle ci-dessous

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

Essayez ensuite ce qui suit

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

4 votes

+1 Ça marche bien pour le scénario d'échange, mais j'ai l'impression qu'une rotation est nécessaire.

0 votes

C'est plus ou moins ce que j'ai fait de toute façon, mais merci pour l'explication de la raison pour laquelle il n'y a apparemment pas de meilleure façon :)

6 votes

Pour la gestion des erreurs, notez que vous devez vérifier le paramètre FindIndex la valeur du résultat, c'est -1 si l'élément n'est pas trouvé dans la liste.

47voto

Grizzly Points 11329

Linq fonctionne généralement sur les Enumérables, donc il ne sait pas si le type sous-jacent est une collection. Donc pour déplacer l'élément en haut de la liste, je suggérerais d'utiliser quelque chose comme (si vous avez besoin de préserver l'ordre)

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

Si votre fonction ne renvoie qu'un IEnumerable, vous pouvez utiliser la fonction ToList() pour le convertir en une liste

Si vous ne voulez pas préserver l'ordre, vous pouvez simplement échanger les valeurs à la position 0 et à la position idx.

0 votes

C'est parfait pour le scénario de rotation vers le bas au lieu de simplement échanger les valeurs.

11voto

configurator Points 15594

Voici une méthode d'extension que vous pourriez utiliser. Elle déplace le ou les éléments qui correspondent au prédicat donné vers le haut, en préservant l'ordre.

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

En termes de complexité, je pense qu'elle ferait deux passages sur la collection, ce qui la rendrait O(n), comme la version Insert/Remove, mais mieux que la suggestion OrderBy de Jon Skeet.

1voto

Il est intéressant de voir le nombre d'approches que l'on trouve lorsqu'on essaie de résoudre un problème.

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);

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X