04. oktober 2010 - 20:56Der er
12 kommentarer og 1 løsning
Bedste måde at merge 2 generiske lister af samme type?
Hejsa.
Ville lige have input her. Jeg har løst mit "problem", men nok ikke på den pæneste måde, rent kodemæssigt.
Derfor vil jeg lige høre hvordan i ville gøre det.
1. Jeg har en generisk liste (A) af typen 'List<Order>'. Den indeholder en masse ordrer.
2. Jeg har så en generisk liste (B) af samme type som indeholder nogle af de samme ordrer fra databasen, men hvor nogle properties er blevet ændret/opdateret.
Hvordan merger man de 2 lister på den nemmeste måde? Objekterne i de 2 lister er ikke de samme instancer, da den ene liste (A) er oprettet fra en lokal cache, mens den anden (B) hele tiden får sine data direkte fra databasen.
'Order' objektet har en Int property kaldet 'Id' som skal bruges til at identificerer objekterne.
Det skal ALTID være objektet fra liste (A) som skal slettes og erstattes med objektet fra liste (B).
Det skal lige tilføjes at objekterne i liste B som sagt kan være til stede i liste A. Men hvis det nu er nye ordrer som er oprettet efter liste A blev cachet, så vil de kun findes i liste B og skal derfor tilføjes til liste A.
Her er en Merge metode med 3 linier og O(n) egenskaber:
using System; using System.Collections.Generic; using System.Linq;
namespace E { public class Data { public int Id { get; set; } public string Val { get; set; } } public static class MyExtensions { public static List<T> Merge<T,T2>(this List<T> oldlst, List<T> newlst, Func<T, T2> kg) { Dictionary<T2,T> res = oldlst.ToDictionary<T,T2>(kg); newlst.ForEach(o => res[kg(o)] = o); return res.Values.ToList(); } } public class Program { public static void Main(string[] args) { List<Data> oldlst = new List<Data>{ new Data { Id=1, Val="Old val 1" }, new Data { Id=2, Val="Old val 2" }, new Data { Id=3, Val="Old val 3" }}; foreach(Data o in oldlst) { Console.WriteLine(o.Id + " : " + o.Val); } List<Data> newlst = new List<Data>{ new Data { Id=2, Val="New val 2" }, new Data { Id=4, Val="New val 4" }}; foreach(Data o in newlst) { Console.WriteLine(o.Id + " : " + o.Val); } List<Data> res = oldlst.Merge(newlst, o => o.Id); foreach(Data o in res) { Console.WriteLine(o.Id + " : " + o.Val); } Console.ReadKey(); } } }
Her er en anden løsning som bruger Linq Union. Den kræver at du overwriter Equals og GetHashCode på din Order klasse. Eller kan du implementere en custom klasse som implementerer IEqualityComparer<T>.
using System.Collections.Generic; using System.Linq;
namespace ConsoleApplication2 { internal class Program { private static void Main(string[] args) { var cachedList = new List<Order> { new Order(0, 1), new Order(1, 1), new Order(2, 1), new Order(3, 1), new Order(4, 1), new Order(5, 1), new Order(6, 1), new Order(7, 1), };
var dbList = new List<Order> { new Order(0, 2), new Order(1, 2), new Order(8, 2), new Order(9, 2), };
Janus, det var jo lige den løsning jeg håbede fandtes, men bare ikke lige var kommet på selv :-)
Takker for svar alle. Jeg vælger helt klart at bruge den løsning Janus kommer med. Lambda expressions er så cool. Jeg har lidt at læse op på der endnu, for hold da op hvor kan man bare lave kodeoptimering der :-)
Nærlæste lige arnes, den er nu heller ikke tosset. Kan godt li idéen med en Merge extension :) selvom den ikke fjerner dem der allerede findes, men det kan jo fikses :)
kode kompleksitet: 1 temporær variabel + 3 metode kald performance karakteristika: O(n) side effekter: ingen restriktioner: ingen
#4
kode kompleksitet: 1 metode kald performance karakteristika: ikke dokumenteret men brug af Reflector og test siger O(n) side effekter: ingen restriktioner: kræver Equals & GetHashCode i data klasser
#5
kode kompleksitet: 7 metode kald performance karakteristika: O(n*n) side effekter: ændrer input restriktioner: ingen
Synes godt om
Ny brugerNybegynder
Din løsning...
Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] Web- og emailadresser omdannes automatisk til links. Der sættes "nofollow" på alle links.