Avatar billede lasserasch Juniormester
04. oktober 2010 - 20:56 Der 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).

Nogle inputs?

Mvh.
Lasse
Avatar billede lasserasch Juniormester
04. oktober 2010 - 20:59 #1
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.

MVh.
Lasse
Avatar billede lasserasch Juniormester
04. oktober 2010 - 21:15 #2
Dette er den løsning jeg har nu.

Men som i nok kan se, så er den ikke helt optimal :-)


  public static List<Order> MergeLists(List<Order> CachedList, List<Order> DBList)
        {

            List<Order> ReplaceList = new List<Order>();
            List<Order> AddList = new List<Order>();
            foreach (Order o1 in DBList)
            {
                bool Found = false;
                foreach (Order o2 in CachedList)
                {
                    if (o1.Id == o2.Id)
                    {
                        ReplaceList.Add(o2);
                        Found = true;
                    }
                }
                if (!Found)
                    AddList.Add(o1);
            }

            foreach (Order o1 in ReplaceList)
            {
                CachedList.Remove(o1);
                foreach (Order o2 in DBList)
                {
                    if (o1.Id == o2.Id)
                        CachedList.Add(o2);
                }
            }
            foreach (Order o in AddList)
            {
                CachedList.Add(o);
            }
            return CachedList;
        }
Avatar billede arne_v Ekspert
04. oktober 2010 - 22:59 #3
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();
        }
    }
}
Avatar billede Pulchra Nybegynder
04. oktober 2010 - 23:51 #4
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),
                            };


            List<Order> updatedCachedList = dbList.Union(cachedList).ToList();
        }
    }

    public class Order
    {
        private readonly int _id;
        private readonly int _type;

        public Order(int id, int type)
        {
            _id = id;
            _type = type;
        }

        public int Id
        {
            get { return _id; }
        }

        public override bool Equals(object obj)
        {
            // Try to cast the object to compare to to be a Order
            var order = obj as Order;

            //Check whether the compared objects reference the same data.
            if (ReferenceEquals(this, order))
                return true;

            //Check whether the compared objects is null.
            if (ReferenceEquals(order, null))
                return false;

            return _id == order._id;
        }

        public override int GetHashCode()
        {
            return _id.GetHashCode();
        }

        public override string ToString()
        {
            return "Person (" + _id + "," + _type + ")";
        }
    }
}
Avatar billede janus_007 Nybegynder
05. oktober 2010 - 12:34 #5
Nu inden det tager helt overhånd med 120 linjer kode, så...

List<Order> cachedList = new List<Order>();
List<Order> dbList= new List<Order>();


Fjern alle som er cachet...
cachedList.RemoveAll(x => dbList.Select(y => y.Id).Contains(x.Id));

Tilføj nye:
dbList.AddRange(cachedList.Where(y => !dbList.Select(u => u.Id).Contains(y.Id)));
Avatar billede Pulchra Nybegynder
05. oktober 2010 - 12:48 #6
Hvem bruger 120 linjer af kode?
Tror faktisk at min løsning fylder en enkel :)
Avatar billede janus_007 Nybegynder
05. oktober 2010 - 12:54 #7
Skal nok være:
cachedList.AddRange(dbList.Where(y => !cachedList.Select(u => u.Id).Contains(y.Id)));

:)
Avatar billede janus_007 Nybegynder
05. oktober 2010 - 12:55 #8
hey Pulchra

Ikke med dine overrides
Avatar billede lasserasch Juniormester
05. oktober 2010 - 13:30 #9
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 :-)



Smid svar for point.

Mvh.
Lasse
Avatar billede janus_007 Nybegynder
05. oktober 2010 - 17:36 #10
Jeps... I love'em :)
Udviklerlivet ville jo slet ikke være det samme uden *S*
Avatar billede janus_007 Nybegynder
05. oktober 2010 - 17:41 #11
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 :)
Avatar billede arne_v Ekspert
16. oktober 2010 - 04:21 #12
Dem der skal fjernes bliver fjernet ved at de bliver overskrevet i Dictionary.
Avatar billede arne_v Ekspert
16. oktober 2010 - 04:30 #13
Man kan jo sammenligne løsningerne:

#3

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
Avatar billede Ny bruger Nybegynder

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.

Loading billede Opret Preview
Kategori
IT-kurser om Microsoft 365, sikkerhed, personlig vækst, udvikling, digital markedsføring, grafisk design, SAP og forretningsanalyse.

Log ind eller opret profil

Hov!

For at kunne deltage på Computerworld Eksperten skal du være logget ind.

Det er heldigvis nemt at oprette en bruger: Det tager to minutter og du kan vælge at bruge enten e-mail, Facebook eller Google som login.

Du kan også logge ind via nedenstående tjenester