Czy istnieje sposób na przeniesienie elementu powiedzmy id = 10 jako pierwszego elementu na liście przy użyciu LINQ?
Pozycja A - id = 5 Pozycja B - id = 10 Pozycja C - id = 12 Pozycja D - id = 1
W takim przypadku jak mogę elegancko przenieść element C na początek mojej List<T>
kolekcji?
Oto najlepsze, jakie mam teraz:
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();
Odpowiedzi:
LINQ jest skuteczny w wykonywaniu zapytań dotyczących kolekcji, tworzeniu prognoz na istniejące zapytania lub generowaniu nowych zapytań na podstawie istniejących kolekcji. Nie jest to narzędzie do ponownego zamawiania istniejących kolekcji w trybie inline. Do tego typu operacji najlepiej używać tego typu.
Zakładając, że masz typ o podobnej definicji jak poniżej
class Item { public int Id { get; set; } .. }
Następnie spróbuj wykonać następujące czynności
List<Item> list = GetTheList(); var index = list.FindIndex(x => x.Id == 12); var item = list[index]; list[index] = list[0]; list[0] = item;
źródło
FindIndex
wartość wyniku, jest to -1, jeśli element nie zostanie znaleziony na liście.Co chcesz zamówić, oprócz znanego topowego przedmiotu? Jeśli cię to nie obchodzi, możesz to zrobić:
var query = allCountries.OrderBy(x => x.id != 592).ToList();
Zasadniczo „fałsz” występuje przed „prawda” ...
Wprawdzie nie wiem, co to robi w LINQ to SQL itp. Być może trzeba będzie powstrzymać go od wykonywania kolejności w bazie danych:
var query = allCountries.AsEnumerable() .OrderBy(x => x.id != 592) .ToList();
źródło
Name
małą listę na górze lub indeks 0, w LINQ to Entities, i to załatwiło sprawę dzięki +1.db.Systms.Where(s => s.IsActive == true).OrderBy(x => x.SystemName != "Portal Administration").ToList();
Linq generalnie działa na Enumerables, więc teraz nie jest, że typem bazowym jest kolekcja. Więc do przeniesienia pozycji na górę listy sugerowałbym użycie czegoś takiego (jeśli chcesz zachować kolejność)
var idx = myList.FindIndex(x => x.id == 592); var item = myList[idx]; myList.RemoveAt(idx); myList.Insert(0, item);
Jeśli funkcja zwraca tylko element IEnumerable, możesz użyć
ToList()
metody, aby najpierw przekonwertować ją na ListęJeśli nie zachowasz kolejności, możesz po prostu zamienić wartości na pozycji 0 i pozycji idx
źródło
var allCountries = repository.GetCountries(); allCountries.OrderByDescending(o => o.id == 12).ThenBy(o => o.id)
Spowoduje to wstawienie obiektu o id = 12 na górze listy i obrócenie reszty w dół, zachowując kolejność.
źródło
Oto metoda rozszerzenia, której możesz chcieć użyć. Przenosi element (y) pasujące do danego predykatu na górę, zachowując kolejność.
public static IEnumerable<T> MoveToTop(IEnumerable<T> list, Func<T, bool> func) { return list.Where(func) .Concat(list.Where(item => !func(item))); }
Jeśli chodzi o złożoność, myślę, że zrobiłby to dwa przejścia w kolekcji, czyniąc ją O (n), podobnie jak wersja Insert / Remove, ale lepiej niż sugestia Jona Skeeta OrderBy.
źródło
Możesz „grupować według” w dwie grupy za pomocą klucza boolowskiego, a następnie je sortować
var finalList= allCountries .GroupBy(x => x.id != 592) .OrderBy(g => g.Key) .SelectMany(g => g.OrderBy(x=> x.id ));
źródło
Wiem, że to stare pytanie, ale zrobiłem to w ten sposób
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(); } }
to drukuje:
liczba to 10
liczba to 1
liczba to 5
liczba to 12
źródło
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; }
źródło
Interesująca jest liczba podejść, które można znaleźć, próbując rozwiązać 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);
źródło
Aby również sprawdzić, czy element został znaleziony bez wyjątku, na przykład:
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();
źródło
W tym celu napisałem statyczną metodę rozszerzenia. Pamiętaj, że to nie zachowuje kolejności, po prostu zamienia element. Jeśli chcesz zachować kolejność, powinieneś wykonać rotację, a nie prostą zamianę.
/// <summary> /// Moves the item to the front of the list if it exists, if it does not it returns false /// </summary> /// <typeparam name="T"></typeparam> /// <param name="collection"></param> /// <param name="predicate"></param> /// <returns></returns> public static bool MoveToFrontOfListWhere<T>(this List<T> collection, Func<T, bool> predicate) { if (collection == null || collection.Count <= 0) return false; int index = -1; for (int i = 0; i < collection.Count; i++) { T element = collection.ElementAt(i); if (!predicate(element)) continue; index = i; break; } if (index == -1) return false; T item = collection[index]; collection[index] = collection[0]; collection[0] = item; return true; }
źródło