Avatar billede chrisrj Forsker
21. juni 2021 - 16:36 Der er 14 kommentarer og
2 løsninger

Dynamisk filter på liste af objekter?

Hejsa


Jeg har en liste(LawCollection) med nogle objekter(LawItem), og jeg vil gerne have en funktion der kan lave en filtreret liste.

Hvordan gør jeg det?

Mine objekter indeholder strenge, og een boolean - og det skal gerne være muligt at filtrere helt dynamisk.
Avatar billede arne_v Ekspert
21. juni 2021 - 17:06 #1
LINQ og Where på din List må kunne gøre det.
Avatar billede chrisrj Forsker
21. juni 2021 - 17:09 #2
Doh, naturligvis!

Sad vist og sov her... :D
Avatar billede chrisrj Forsker
21. juni 2021 - 17:12 #3
Arg, men det er jo kun halvdelen af løsningen! :D

Filterne kommer fra nogle dropdownbokse i et array.

Noget ala dette(har ikke helt lavet den del endnu ;)):
box1,(filterværdi)
box3,(filterværdi)
osv..

Hvordan får jeg dét ind i min where uden et mega udpindingsarbejde?
Avatar billede arne_v Ekspert
21. juni 2021 - 17:30 #4
Lad mig prøve og lave et eksempel.
Avatar billede arne_v Ekspert
21. juni 2021 - 17:46 #5

using System;
using System.Collections.Generic;
using System.Linq;

namespace E
{
    public class Data
    {
        public int Iv { get; set; }
        public string Sv { get; set; }
    }
    public class Program
    {
        public static List<Data> Filter(List<Data> lst, int? iv, string sv)
        {
            IEnumerable<Data> res = lst;
            if(iv != null)
            {
                res = res.Where(o => o.Iv == (int)iv);
            }
            if(sv != null)
            {
                res = res.Where(o => o.Sv == sv);
            }
            return res.ToList();
        }
        public static void Dump(List<Data> lst)
        {
            foreach(Data o in lst)
            {
                Console.WriteLine("{0} {1}", o.Iv, o.Sv);
            }
        }
        public static void Test(List<Data> lst, int? iv, string sv)
        {
            Console.WriteLine("Filter: {0} {1}", iv, sv);
            Dump(Filter(lst, iv, sv));
        }
        public static void Main(string[] args)
        {
            List<Data> lst = new List<Data> { new Data { Iv = 1, Sv = "A" }, new Data { Iv = 2, Sv = "BB" }, new Data { Iv = 3, Sv = "CCC" }, new Data { Iv = 3, Sv = "A" } };
            Test(lst, 1, null);
            Test(lst, 3, null);
            Test(lst, null, "A");
            Test(lst, null, "BB");
            Test(lst, 3, "CCC");
            Console.ReadKey();
        }
    }
}
Avatar billede arne_v Ekspert
21. juni 2021 - 17:47 #6
Eksemplet har ikke nogle GUI felter men har værdier og null betyder ingen filtrering for feltet.
Avatar billede chrisrj Forsker
21. juni 2021 - 18:47 #7
Hmmm...

Interessant, jeg kigger på det i morgen. :)
Avatar billede chrisrj Forsker
22. juni 2021 - 12:47 #8
Så har jeg testet det, og det virker (naturligvis ;) ).

Omformet til mine objekter virker det også. Yay. :)

Meeen :D det virker en smule omstændigt, da jeg har over 10 bokse.

Såehm....er det VILDT besværligt at lave det mere dynamisk? :)
Avatar billede arne_v Ekspert
22. juni 2021 - 14:03 #9
Den kritiske kode er:


        public static List<Data> Filter(List<Data> lst, int? iv, string sv)
        {
            IEnumerable<Data> res = lst;
            if(iv != null)
            {
                res = res.Where(o => o.Iv == (int)iv);
            }
            if(sv != null)
            {
                res = res.Where(o => o.Sv == sv);
            }
            return res.ToList();
        }


Hvis du er manisk med at tælle linier kan du omskrive til:


        public static List<Data> Filter(List<Data> lst, int? iv, string sv)
        {
            IEnumerable<Data> res = lst;
            if(iv != null) res = res.Where(o => o.Iv == (int)iv);
            if(sv != null) res = res.Where(o => o.Sv == sv);
            return res.ToList();
        }


:-)

Men jeg formoder at det er 1 if test per potentiel filter felt som generer dig.

Man kunne godt lave en helt generel filter funktion som kun sendte felt/property navne og værdier over.

Men den ville skulle tilgå properties via reflection og det vil både koste i performance og gøre koden mindre type sikker.
Avatar billede chrisrj Forsker
22. juni 2021 - 14:09 #10
Hehe, jaeh, det var ikke så meget linieantallet jeg har problemer med. ;)

Men jeg kan se på det hele, at det jeg vil, ikke er det smarteste. :D

Jeg takker for løsningen - og inputtet. :)
Avatar billede arne_v Ekspert
22. juni 2021 - 14:47 #11
Jeg tror at det at opbygge LINQ Where er den rigtige løsning. Det giver lidt kode, men det er læsbar kode og det performer rimeligt godt (husk at en Where *ikke* laver en ny kopi af data - der først ToList som laver en ny kopi af data).

public static List<Data> Filter(List<Data> lst, string[] propnames, object[] valuies)

vil komme med overhead af reflection og hvis en propname ikke finde i objekt så kommer der en runtime fejl fremfor en compile time fejl.

Så er der mere eksotisk løsninger:

* generere C# kode med filter udfra propnames+values, kalde C# compileren runtime og dynamiske loade resulatet

* generere noget script kode og embedde en script engine i programet og lade filter koden bruge det

Men det er altså sådan noget der for maintenance programmers til at sige WTF????
Avatar billede chrisrj Forsker
22. juni 2021 - 14:52 #12
Det var også mit første gæt, men jeg kunne ikke umiddelbart få det til at virke... ;)

LOL! :D Så er det godt, at det kun er et hobby projekt! :D
Avatar billede arne_v Ekspert
22. juni 2021 - 14:56 #13
Den med "maintenance programmers" var for de to såkaldte "eksotisk løsninger".
Avatar billede chrisrj Forsker
22. juni 2021 - 14:58 #14
Det er jeg helt med på. :)
Avatar billede arne_v Ekspert
22. juni 2021 - 15:25 #15
Hvis du vil lege med at embedde script fortolkning så er der kode her:

https://www.vajhoej.dk/arne/articles/call1.html#clr_toscript
Avatar billede chrisrj Forsker
22. juni 2021 - 15:29 #16
Tak tak, det er faktisk alt for meget... :D
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

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