Avatar billede mcnovy Nybegynder
03. juni 2006 - 20:04 Der er 20 kommentarer og
1 løsning

Foreach løkke, hvor at Arraylist bliver ændret i lykken

Hey eksperter

jeg har en foreach løkke som følgende

foreach (ArrMappeObj in ArrMappe)
{
}

hvor arrMappeObj som det næsten siger, er et objekt :)
og ArrMappe er en ArrayList

selve min foreach løkke virker fint.
men indeni min løkke, der tilføjer jeg nogle objekter til ArrMappe
i korte træk som følgende:

foreach (ArrMappeObj in ArrMappe)
{
newMappe(tmp1, tmp2);
}

private void newMappe(string tmp1, string tmp2)
{
ArrMappeObj TEST = new ArrMappeObj(tmp1, tmp2);
ArrMappe.Add(TEST);
}

håber at det er nok til at det giver bare en smule mening.

men idet at jeg tilføjer et objekt i min foreach løkke, så laver den en fejl, som lyder som følgende:

Collection was modified; enumeration operation may not execute.

er der nogen der har en idé om hvordan man kan få tilladelse til at lade løkken være "dynamisk"

eller om hvordan man eller kan gøre..?
en while struktur burde vel kunne gøre det.. men ville helst bruge Foreach

int i = 0;
while (i <= ArrMappe.Count && ArrMappe > 0)
{
newMappe(tmp1, tmp2);
i++;
}

private void newMappe(string tmp1, string tmp2)
{
ArrMappeObj TEST = new ArrMappeObj(tmp1, tmp2);
ArrMappe.Add(TEST);
}

kunne vel godt bruges..
nok med nogle ændringer..

men er en while eller en do/while løkke den korrekte måde at komme igennem helle array på..?
Avatar billede nielle Nybegynder
03. juni 2006 - 20:12 #1
Hvorfor ønsker du at tilføje til din ArrayList som en del af din løkke?

Og hvad skal der ske med de nye elementer? Skal foreach-løkken også løbe igennem dem, eller skal den springe over dem?
Avatar billede arne_v Ekspert
03. juni 2006 - 20:14 #2
at tilføje til eller slette fra noget mens du enumererer over det er ikke godt

du bør kunne få en while løkke til at virke

men du kunne også overveje at tilføje til en ny temporær ArrayList og så
tilføje alle elementer i den til din eksisterende ArrayList efter løkken
Avatar billede mcnovy Nybegynder
03. juni 2006 - 20:16 #3
det er en slags Directory liste jeg skal lave.

og det er den eneste måde jeg selv lige kan komme på...!

dvs hvis min kode skulle være lidt mere præcis skrevet ind her, så er der en foreach løkke, I løkken :)
og den foreach løkke, den kigger alle undermapperne igennem, og ser om de er i min dB i forvejen.

og de nye elementer skal også være en del af løkken, altså den skal IKKE springe dem over..!
Avatar billede mcnovy Nybegynder
03. juni 2006 - 20:17 #4
arne v.

ja.. kunne man godt..
men så vil de elementer jo ikke bliver kigget igennem :)
Avatar billede arne_v Ekspert
03. juni 2006 - 20:17 #5
du kunne jo checke den nye liste til sidste
Avatar billede nielle Nybegynder
03. juni 2006 - 20:33 #6
Det lægger op til en rekursiv løsning:

        static void Main(string[] args)
        {
            OpdaterArrMappeRekursivt(ArrMappe);
        }

        private static void OpdaterArrMappeRekursivt(ArrayList TempArrMappe1)
        {
            ArrayList TempArrMappe2 = new ArrayList();

            foreach (ArrMappeObj ArrMappeObj in TempArrMappe1)
            {
                ArrMappeObj TEST = new ArrMappeObj(tmp1, tmp2);
                TempArrMappe2.Add(TEST);
            }

            foreach (ArrMappeObj ArrMappeObj in TempArrMappe2)
            {
                ArrMappe.Add(ArrMappeObj);
            }

            OpdaterArrMappeRekursivt(TempArrMappe2);
        }
Avatar billede mcnovy Nybegynder
03. juni 2006 - 20:35 #7
ja.. kunne man godt.. men det ville i principet jo bare betyde at man Copy & paste hele den samme kode til at køre igen..
det er der jo ingen grund til..
ellers skulle man lave den til en metode, og så lade den kører igennem nogle gange.!

jeg må nok hellere være mere præcis

jeg skal lave en directory listing..
den directory listing laver jeg på følgende måde

hmm. tror bare jeg poster noget af selve koden..
undskyld hvis det er noget sjusk at læse

  class FileGenerator
    {

        private ArrayList ArrMappe = new ArrayList();
        private string StiTildB = @"c:\db.mdb";
        private string Mappe = "";
        FileInfo Fil;
        DirectoryInfo Mappe;

        public FileGenerator()
        {
            bool NytIDb = false;
            User u = new User();
            string Mappe = u.HomeDir;
            HentHeleDb();
            if (0 < ArrMappe.Count)
            {

                foreach (ArrMappeObj tmpInfo in ArrMappe)
                {
                    Mappe = new DirectoryInfo(tmpInfo.MappeSti);
                    if (Mappe.LastWriteTime != tmpInfo.LastChange)
                    {
                        NytIDb = true;
                        break;
                    }
                }

            }
            else
            {
                Mappe = new DirectoryInfo(Mappe);
                DateTime LastChange = new DateTime();
                NewMappe(Mappe, LastChange);
                if (ArrMappe.Count > 0) NytIDb = true;
            }
            if (NytIDb == true)
            {
                if (ArrMappe.Count > 0)
                {
                    foreach (ArrMappeObj tmpInfo in ArrMappe)
                    {
                        Mappe = new DirectoryInfo(tmpInfo.MappeSti);
                        if (Mappe1.LastWriteTime != tmpInfo.LastChange)
                        {
                            ArrayList Arrtmp = new ArrayList();
                            Arrtmp.AddRange(Mappe.GetDirectories());
                            ArrayList ArrMappetmp = new ArrayList();
                            ArrMappetmp.AddRange(ArrMappe);
                            foreach (DirectoryInfo DI in Arrtmp)
                            {
                                bool FindesDet = false;

                                foreach (ArrMappeObj tmpInfo0 in ArrMappetmp)
                                {
                                    if (DI.FullName == tmpInfo0.MappeSti)
                                    {
                                        FindesDet = true;
                                        break;
                                    }
                                }
                                if (FindesDet == false)
                                {
                                    NewMappe(DI.FullName, (new DateTime()));
                                }

                            }
                        }
                    }
                }
            }
        }


jeg har ændret nogle af streng navnene, men ellers er det koden i træk.

det den skal gøre.
i starten er der ikke noget i DB, dvs der skal den tage det dir jeg har bedt den om
derefter går den ind og ser efter undermapper i den mappe, de undermapper skal så tilfæjes array, og kigges igennem (hvor problemet jo er med foreach løkken)
Avatar billede nielle Nybegynder
03. juni 2006 - 20:47 #8
Med rekursivitet behøver du ikke at gentage din kode.

BTW: Du får prøblemer ved at have to forskellige versioner af Mappe:

...
private string Mappe = "";
FileInfo Fil;
DirectoryInfo Mappe;
...
Avatar billede mcnovy Nybegynder
03. juni 2006 - 21:04 #9
nielle

den kode du har givet..
(jeg har ingen erfaring af hvad jeg ved af, om rekursivitet)
men koden du har givet.. den vil vel bare køre i en konstant lykke..?
vil den nogensinde bryde..?
Avatar billede nielle Nybegynder
03. juni 2006 - 21:08 #10
Du har ret i at der var en fejl. Sådan:

            if (TempArrMappe2.Count > 0)
                OpdaterArrMappeRekursivt(TempArrMappe2);
Avatar billede nielle Nybegynder
03. juni 2006 - 21:09 #11
Den bryder når der ikke er fundet noget nyt.
Avatar billede mcnovy Nybegynder
03. juni 2006 - 21:21 #12
skal det være en static void
Avatar billede mcnovy Nybegynder
03. juni 2006 - 21:24 #13
men overvejer lidt om det ikke ville være nemmere at ændre min nuværende kode til en while løsning, frem en "rek.... :) "
du har nok bedre styr på det en mig, så har du nogle gode forslag..?
Avatar billede nielle Nybegynder
03. juni 2006 - 21:25 #14
static - Ikke nødvendigvis. I mit kode-eksempel er den egentlig kun static fordu at den kaldes fra main() som selv er static.

void - Ja, med mindre at du kan finde en mere relevant retur-værdi?
Avatar billede nielle Nybegynder
03. juni 2006 - 21:28 #15
Jeg vil helt klart anbefale en rekursiv løsning.

Se på det fra den lyse side - så lærer du også noget om den teknik, og den er vigtig at beherske, hvis man ønsker at drive det til noget seriøst indenfor programmering. :^)
Avatar billede mcnovy Nybegynder
03. juni 2006 - 21:35 #16
kan du give et kort resume af hvorfor en rekursiv er en god løsning.?
hvis det er, så smider jeg 200 point i puljen..!
Avatar billede nielle Nybegynder
03. juni 2006 - 21:58 #17
Rekursion bruges bedst når et problem kan deles op i mindre problemer som hver især ligner det oprindelige problem.

Det er den situation du har her: Du har brug for at gennemløbe en liste og "gøre noget". Undervejs putter du så mere i listen og har derfor brug for også at gennemløbe disse og "gøre noget". Dermed kommer der atter mere i listen, og også for disse nye elementer har du brug for at "gøre noget". osv. osv.

Rekusion ligger som regel lige til højrebenet når man har en opgave som kræver at man skal gennemløbe et bibliotek og alle dets underbiblioteker: Først gennemløber man bibliotektet, dernæst gennemløber man dettes underbiblioteker, dernæst gennemløber man deres underbiblioteker, osv:

using System;
using System.IO;

namespace e713586c
{
    class Program
    {
        static void Main(string[] args)
        {
            DirectoryInfo scanDi = new DirectoryInfo(@"C:\Programmer");

            VisFiler(scanDi);
        }

        static void VisFiler(DirectoryInfo di)
        {
            // Vis alle filerne i dette bibliotek:
            foreach (FileInfo fi in di.GetFiles())
                Console.WriteLine(fi.FullName);

            // Vis filerne i dette biblioteks underbiblioteker;
            foreach (DirectoryInfo subDi in di.GetDirectories())
                VisFiler(subDi);
        }
    }
}


Et andet almindeligt eksempel, som bruger rekursivitet, er beregning af fakultet (10! = 10*9*8*7*6*5*4*3*2*1):

using System;

namespace e713586d
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Fakultetet af 10 er: " + Fakultet(10));
        }

        static int Fakultet(int n)
        {
            if (n == 1)
                return 1;
            else
                return n * Fakultet(n - 1);
        }
    }
}

Dette er i øvrigt et eksempel på at der ikke altid skal returneres void.


PS: Ingen grund til at hæve point på denne her - 100 points er skam nok.
Avatar billede mcnovy Nybegynder
03. juni 2006 - 22:03 #18
et resume bliver åbenbart hurtigt til et referat..! :)

ej..
det er rigtig lækker info at få smækket i hovedet..!

og jeg kan udmærket godt se at det ihvertfald er denne løsning jeg ledte efter.
(bare en skam jeg ikke spurgte FØR jeg selv begav mig ud i det :) )
men smid et svar.
Avatar billede nielle Nybegynder
03. juni 2006 - 22:06 #19
Svar :^)
Avatar billede mcnovy Nybegynder
03. juni 2006 - 22:09 #20
Takker mange gange for svarene..!
Avatar billede nielle Nybegynder
03. juni 2006 - 22:19 #21
Takke for point :^)
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