myCSharp.de - DIE C# und .NET Community
Willkommen auf myCSharp.de! Anmelden | kostenlos registrieren
 
 | Suche | FAQ

» Hauptmenü
myCSharp.de
» Startseite
» Forum
» FAQ
» Artikel
» C#-Snippets
» Jobbörse
» Suche
» Regeln
» Wie poste ich richtig?
» Forum-FAQ

Mitglieder
» Liste / Suche
» Wer ist wo online?

Ressourcen
» openbook: Visual C#
» openbook: OO
» Microsoft Docs

Team
» Kontakt
» Übersicht
» Wir über uns

» myCSharp.de Diskussionsforum
Du befindest Dich hier: Community-Index » Diskussionsforum » Entwicklung » Basistechnologien und allgemeine .NET-Klassen » foreach iteration gleichzeitig über mehrere arrays
Letzter Beitrag | Erster ungelesener Beitrag Druckvorschau | Thema zu Favoriten hinzufügen

Antwort erstellen
Zum Ende der Seite springen  

foreach iteration gleichzeitig über mehrere arrays

 
Autor
Beitrag « Vorheriges Thema | Nächstes Thema »
renexxl
myCSharp.de-Mitglied

Dabei seit: 01.02.2005
Beiträge: 51


renexxl ist offline

foreach iteration gleichzeitig über mehrere arrays

Beitrag: beantworten | zitieren | editieren | melden/löschen       | Top

Hallo!

Bei mir häufen sich die Fälle, in denen ich mit foreach über mehrere arrays gleichzeitig iterieren möchte, um redundanten Code zu vermeiden.
Beispiel:

C#-Code:
int[] numbers0 = { 1, 2, 3 };
int[] numbers1 = { 4, 5, 6 };

foreach (int i in numbers0)
{
    System.Console.WriteLine(i);
}

foreach (int i in numbers1)
{
    System.Console.WriteLine(i);
}

Stattdessen möchte ich in einer foreach Schleife beide arrays gleichzeitig abarbeiten.
Dies könnte z.B. folgendermaßen aussehen:

C#-Code:
foreach (int i in numbers0 + numbers1)
{
    System.Console.WriteLine(i);
}

Insbesondere bei vielen arrays erzeugt man schnell redundanten Code.

Ich könnte mir natürlich ein temporäres Array erzeugen und numbers0 und numbers1 dort reinkopieren. Dies würde aber unnötigen Overhead erzeugen.

- Rene
14.02.2006 09:05 E-Mail | Beiträge des Benutzers | zu Buddylist hinzufügen
norman_timo norman_timo ist männlich
myCSharp.de-Mitglied

avatar-1775.jpeg


Dabei seit: 13.07.2004
Beiträge: 4.506
Entwicklungsumgebung: .NET 2.0/3.5 und VS2005/VS2008
Herkunft: Wald-Michelbach (Odw)


norman_timo ist offline

Beitrag: beantworten | zitieren | editieren | melden/löschen       | Top

Hallo renexxl,

in Deinen Fällen würde ich schlicht auf die Foreach-Anweisung verzichten und eine klassische For-Schleife verwenden:

C#-Code:
for (int i=0; i<numbers0.Count; i++)
{
   Console.Writeline(numbers0[i]);
   Console.Writeline(numbers1[i]);
}

Das Ganze funktioniert aber nur, wenn beide arrays gleich viele Einträge haben (um genau zu sein muss numbers1 genausoviele, oder mehr Einträge besitzen).

Ciao
Norman-Timo

Dieser Beitrag wurde 1 mal editiert, zum letzten Mal von norman_timo am 14.02.2006 09:10.

14.02.2006 09:09 E-Mail | Beiträge des Benutzers | zu Buddylist hinzufügen
herbivore
myCSharp.de-Poweruser/ Experte

avatar-2627.gif


Dabei seit: 11.01.2005
Beiträge: 49.478
Entwicklungsumgebung: csc/nmake (nothing is faster)
Herkunft: Berlin


herbivore ist offline

Beitrag: beantworten | zitieren | editieren | melden/löschen       | Top

Hallo norman_timo,

dein Code verändert aber die Reihenfolge der Ausgabe und löst daher das eigentliche Problem nicht.

Hallo renexxl,

du kannst dir natürlich einen eigenen Enumerator schreiben, aber vielleicht ist auch schon die grundlegende Speicherung unangemessen. Also das der "Fehler" im Design schon darin liegt, dass du mehrere Arrays verwendest. Das ist aber schwierig zu beurteilen, ohne die Aufgabenstellung zu kennen.

herbivore
14.02.2006 09:22 E-Mail | Beiträge des Benutzers | zu Buddylist hinzufügen
talla talla ist männlich
myCSharp.de-Poweruser/ Experte

avatar-3214.jpg


Dabei seit: 20.07.2003
Beiträge: 6.862
Entwicklungsumgebung: VS 2010
Herkunft: Esslingen


talla ist offline

Beitrag: beantworten | zitieren | editieren | melden/löschen       | Top

Deine foreach Schleife wird doch eh zu ner for Schleife optimiert wenn du primitive Datentypen nimmst. Von daher ists nur syntaktischer Zucker Augenzwinkern Foreach macht nur Sinn wenn du die Funktionen aus IEnumerator und IEnumeralbe implementierst.
14.02.2006 09:23 E-Mail | Beiträge des Benutzers | zu Buddylist hinzufügen
sheitman sheitman ist männlich
myCSharp.de-Mitglied

Dabei seit: 02.11.2005
Beiträge: 1.047


sheitman ist offline

Beitrag: beantworten | zitieren | editieren | melden/löschen       | Top

Zitat:
Bei mir häufen sich die Fälle, in denen ich mit foreach über mehrere arrays gleichzeitig iterieren möchte, um redundanten Code zu vermeiden.

was heißt denn gleichzeitig?

Zitat:
Insbesondere bei vielen arrays erzeugt man schnell redundanten Code.

warum schreibst du dir nicht einfach eine methode die als parameter ein array bekommt und dieses dann ausgibt?

Zitat:
Ich könnte mir natürlich ein temporäres Array erzeugen und numbers0 und numbers1 dort reinkopieren. Dies würde aber unnötigen Overhead erzeugen.

was soll das werden?

Dieser Beitrag wurde 1 mal editiert, zum letzten Mal von sheitman am 14.02.2006 09:39.

14.02.2006 09:37 E-Mail | Beiträge des Benutzers | zu Buddylist hinzufügen
renexxl
myCSharp.de-Mitglied

Dabei seit: 01.02.2005
Beiträge: 51

Themenstarter Thema begonnen von renexxl

renexxl ist offline

Beitrag: beantworten | zitieren | editieren | melden/löschen       | Top

Zitat:
Deine foreach Schleife wird doch eh zu ner for Schleife optimiert wenn du primitive Datentypen nimmst.

Mein Beispiel benutzt einen primitiven Datentyp, in der Praxis nutze ich zumeist nicht primitive Datentypen. Was würde es mir bringen direkt eine for-Schleife zu benutzen?

Zitat:
was heißt denn gleichzeitig?

Mit "gleichzeitig" meine ich "sequentiell innerhalb !einer! foreach-Schleife".

Zitat:
warum schreibst du dir nicht einfach eine methode die als parameter ein array bekommt und dieses dann ausgibt?

Wäre eine Möglichkeit. Ich bin aber der Meinung, dass mein Vorschlag (mit dem +) den Code noch lesbarer macht.

Zitat:
was soll das werden?

Man könnte sich eine Methode schreiben, welche Arrays als Parameter erhält und ein Array als Konkatenation dieser arrays zurückgibt. Ueber das konkatenierte Array kann man dann in einer foreach-Schleife iterieren.
14.02.2006 10:11 E-Mail | Beiträge des Benutzers | zu Buddylist hinzufügen
herbivore
myCSharp.de-Poweruser/ Experte

avatar-2627.gif


Dabei seit: 11.01.2005
Beiträge: 49.478
Entwicklungsumgebung: csc/nmake (nothing is faster)
Herkunft: Berlin


herbivore ist offline

Beitrag: beantworten | zitieren | editieren | melden/löschen       | Top

Hallo renexxl,

hier kommt die Klasse MetaCollection, mit der du genau das tun kannst, was du willst.

EDIT: Weiter unten gibt es eine  typsichere Implementierung, die vorzuziehen ist.

C#-Code:
foreach (int i in new MetaCollection (numbers0, numbers1)) {
   System.Console.WriteLine (i);
}

C#-Code:
using System;
using System.Collections;

public class MetaCollection : IEnumerable
{
   private ICollection [] _aicoll;

   internal class MetaCollectionEnumerator : IEnumerator
   {
      private MetaCollection _mcoll;
      private int            _iPos;
      private IEnumerator    _ienum;

      internal MetaCollectionEnumerator (MetaCollection mcoll)
      {
         _mcoll = mcoll;
         Reset ();
      }

      public Object Current
      {
         get { return _ienum == null ? null : _ienum.Current; }
      }

      public bool MoveNext ()
      {
         while (_ienum == null || !_ienum.MoveNext ()) {
            if (++_iPos >= _mcoll._aicoll.Length) { //EDIT: Siehe meine Anmerkung in dem Beitrag weiter unten
               return false;
            }
            _ienum = _mcoll._aicoll [_iPos].GetEnumerator ();
         }

         return true;
      }

      public void Reset ()
      {
         _iPos = -1;
         _ienum = null;
      }

   }

   public MetaCollection (params ICollection [] aicoll)
   {
      _aicoll = aicoll;
   }

   public IEnumerator GetEnumerator ()
   {
      return new MetaCollectionEnumerator (this);
   }
}

abstract class App
{
   public static void Main (string [] astrArg)
   {
      int [] numbers0 = { 1, 2, 3 };
      int [] numbers1 = { 4, 5, 6 };

      foreach (int i in new MetaCollection (numbers0, numbers1)) {
         Console.WriteLine (i);
      }
   }
}

herbivore
14.02.2006 10:38 E-Mail | Beiträge des Benutzers | zu Buddylist hinzufügen
sheitman sheitman ist männlich
myCSharp.de-Mitglied

Dabei seit: 02.11.2005
Beiträge: 1.047


sheitman ist offline

Beitrag: beantworten | zitieren | editieren | melden/löschen       | Top

also herbivores lösung ist ja mal echt extraklasse Daumen hoch

@topicersteller
wär natürlic halles einfacher wenn du im einganstpost schon gesagt hättest was du wirklich machen willst Augenzwinkern

Dieser Beitrag wurde 3 mal editiert, zum letzten Mal von sheitman am 14.02.2006 11:29.

14.02.2006 11:14 E-Mail | Beiträge des Benutzers | zu Buddylist hinzufügen
norman_timo norman_timo ist männlich
myCSharp.de-Mitglied

avatar-1775.jpeg


Dabei seit: 13.07.2004
Beiträge: 4.506
Entwicklungsumgebung: .NET 2.0/3.5 und VS2005/VS2008
Herkunft: Wald-Michelbach (Odw)


norman_timo ist offline

Beitrag: beantworten | zitieren | editieren | melden/löschen       | Top

Hallo Herivore,

Zitat:
dein Code verändert aber die Reihenfolge der Ausgabe und löst daher das eigentliche Problem nicht.

ich hatte das anders verstanden. Ich dachte renexxl wollte die Daten einfach mit einer durchzählung abgreifen. Ich hatte mir keine Gedanken über die Reihenfolge gemacht, da ich der Meinung war, dass wenn ich die Daten in einem Durchgang abgreifen will, dass die Reihenfolge keine Rolle spielt.

Wenn dem natürlich so ist, dann hast Du vollkommen Recht. Daher war meine Lösung von einem anderen Ansatz ausgegangen.


Aber Deine MetaCollection hat echt was für sich ;-)

Ciao
Norman-Timo
14.02.2006 11:25 E-Mail | Beiträge des Benutzers | zu Buddylist hinzufügen
talla talla ist männlich
myCSharp.de-Poweruser/ Experte

avatar-3214.jpg


Dabei seit: 20.07.2003
Beiträge: 6.862
Entwicklungsumgebung: VS 2010
Herkunft: Esslingen


talla ist offline

Beitrag: beantworten | zitieren | editieren | melden/löschen       | Top

Mag schön aussehen, aber mehr als eine auf ICollection typisierte eigene Collection ist es auch nicht smile Aber auf sowas muss man auch erstmal kommen.

Des eigentliche Problem ist ja, dass das Konstrukt nicht typsicher ist, geb mal als Input zwei verschiedentypige Arrays an und schon krachts. Wäre noch nen ausbaufähiger Punkt.

Gruß Talla
14.02.2006 11:32 E-Mail | Beiträge des Benutzers | zu Buddylist hinzufügen
herbivore
myCSharp.de-Poweruser/ Experte

avatar-2627.gif


Dabei seit: 11.01.2005
Beiträge: 49.478
Entwicklungsumgebung: csc/nmake (nothing is faster)
Herkunft: Berlin


herbivore ist offline

Beitrag: beantworten | zitieren | editieren | melden/löschen       | Top

Hallo zusammen,

freut ich, dass es euch gefällt. Perfekt ist die Implementierung allerdings nicht. Habt ihr denn den Fehler gefunden, der in meiner Enumerator-Implementierung steckt?

herbivore
14.02.2006 11:55 E-Mail | Beiträge des Benutzers | zu Buddylist hinzufügen
herbivore
myCSharp.de-Poweruser/ Experte

avatar-2627.gif


Dabei seit: 11.01.2005
Beiträge: 49.478
Entwicklungsumgebung: csc/nmake (nothing is faster)
Herkunft: Berlin


herbivore ist offline

Beitrag: beantworten | zitieren | editieren | melden/löschen       | Top

Hallo zusammen,

ist das Interesse so abgeebbt oder war der Fehler so schwer zu finden?

In der while-Schleife, darf _iPos nur erhöht werden, wenn noch eine weitere Collection in _aicoll vorhanden ist. Also

C#-Code:
if (_iPos >= _mcoll._aicoll.Length - 1) {
   return false;
}
_ienum = _mcoll._aicoll [++_iPos].GetEnumerator ();

statt

C#-Code:
if (++_iPos >= _mcoll._aicoll.Length) {
   return false;
}
_ienum = _mcoll._aicoll [_iPos].GetEnumerator ();

Ansonsten wäre die Forderung an MoveNext

Zitat:
If MoveNext passes the end of the collection, the enumerator is positioned after the last element in the collection and MoveNext returns false. When the enumerator is at this position, subsequent calls to MoveNext also return false until Reset is called.

durch potentielles Überzählen von _iPos nicht gewährleistet, auch wenn der Fehler in der Praxis vermutlich nie zum Tragen gekommen wäre.

Neben diesem Fehler gibt es noch einen Schönheitsfehler, denn die Klasse MetaCollection sollte außer IEnumerable noch ICollection und ICloneable implementieren, um dem Namensbestandteil 'Collection' gerecht zu werden. Die andere Alternative wäre nur die Klasse MetaCollectionEnumerator zu schreiben, analog dem Beispiel MovableEnumerator in  Objekte identifizieren .

herbivore
15.02.2006 09:00 E-Mail | Beiträge des Benutzers | zu Buddylist hinzufügen
renexxl
myCSharp.de-Mitglied

Dabei seit: 01.02.2005
Beiträge: 51

Themenstarter Thema begonnen von renexxl

renexxl ist offline

Beitrag: beantworten | zitieren | editieren | melden/löschen       | Top

Hi Herbivore!

Deine Lösung ist genau das, was ich gesucht habe. Die Idee ist wirklich sehr gut. Respekt!

Ich habe deine Klasse in meiner Applikation eingebaut und bislang keinen Fehler festgestellt. Funktioniert alles wie erwartet.

Vielen Dank!

- Rene
16.02.2006 10:43 E-Mail | Beiträge des Benutzers | zu Buddylist hinzufügen
svenson svenson ist männlich
myCSharp.de-Mitglied

Dabei seit: 15.04.2005
Beiträge: 8.746
Entwicklungsumgebung: Visual Studio .NET 2003
Herkunft: Berlin


svenson ist offline

Beitrag: beantworten | zitieren | editieren | melden/löschen       | Top

Schöne Klasse. Fällt mir auch spontan ein Verwendungszweck ein: Wenn man File-Filter verwendet kommt man bei mehreren, gleichzeitig anzuwendenden Filtern in die Breduille, weil .NET nur Einzel-Filter unterstützt. Als Konsequenz muss man mehrere Einzelcollections abiterieren. Mit der Lösung deutlich einfacher.
16.02.2006 12:14 E-Mail | Beiträge des Benutzers | zu Buddylist hinzufügen
herbivore
myCSharp.de-Poweruser/ Experte

avatar-2627.gif


Dabei seit: 11.01.2005
Beiträge: 49.478
Entwicklungsumgebung: csc/nmake (nothing is faster)
Herkunft: Berlin


herbivore ist offline

Beitrag: beantworten | zitieren | editieren | melden/löschen       | Top

Hallo Talla,

Zitat:
Des eigentliche Problem ist ja, dass das Konstrukt nicht typsicher ist, geb mal als Input zwei verschiedentypige Arrays an und schon krachts. Wäre noch nen ausbaufähiger Punkt.

Naja, ob es kracht, hängt davon ab, welchen Typ die Elementvariable im foreach hat. Solange die typkompatibel zu allen vorhandenen Elementen ist, kracht es nicht.

Ich habe trotzdem mal eine typsichere MetaCollection geschrieben. :-)

Anm.: Da IEnumerator<T2> von IEnumerator erbt und beide eine Current-Methode deklarieren, die sich nur im Rückgabewert unterscheidet, kommt man nicht umhin, mindestens eine Current-Methode interface-explizit zu definieren. Deshalb habe ich im Unterschied zu der untypisierten MetaCollection gleich alle Methoden interface-explizit deklariert.

C#-Code:
using System;
using System.Collections;
using System.Collections.Generic;

public class MetaCollection<T> : IEnumerable<T>
{
   private ICollection<T> [] _aicoll;

   internal class MetaCollectionEnumerator<T2> : IEnumerator<T2>
   {
      private MetaCollection<T2> _mcoll;
      private int                _iPos;
      private IEnumerator<T2>    _ienum;

      internal MetaCollectionEnumerator (MetaCollection<T2> mcoll)
      {
         _mcoll = mcoll;
         Reset ();
      }

      T2 IEnumerator<T2>.Current
      {
         get { return _ienum.Current; }
      }

      Object IEnumerator.Current
      {
         get { return ((IEnumerator<T2>)this).Current; }
      }

      bool IEnumerator.MoveNext ()
      {
         while (_ienum == null || !_ienum.MoveNext ()) {
            if (_iPos >= _mcoll._aicoll.Length - 1) {
               return false;
            }
            _ienum = _mcoll._aicoll [++_iPos].GetEnumerator ();
         }

         return true;
      }

      void IEnumerator.Reset ()
      {
         Reset ();
      }

      private void Reset ()
      {
         _iPos = -1;
         _ienum = null;
      }

      void IDisposable.Dispose ()
      {
         // warum IEnumerator<T> von IDisposable erbt, wird wohl
         // Microsofts Geheimnis bleiben, zumal das IEnumerable<T>
         // und auch ICollection<T> nicht tun.
      }
   }

   public MetaCollection (params ICollection<T> [] aicoll)
   {
      _aicoll = aicoll;
   }

   IEnumerator<T> IEnumerable<T>.GetEnumerator ()
   {
      return new MetaCollectionEnumerator<T> (this);
   }

   IEnumerator IEnumerable.GetEnumerator ()
   {
      return ((IEnumerable<T>)this).GetEnumerator ();
   }
}

abstract class App
{
   public static void Main (string [] astrArg)
   {
      int [] numbers0 = { 1, 2, 3 };
      int [] numbers1 = { 4, 5, 6 };

      foreach (int i in new MetaCollection<int> (numbers0, numbers1)) {
         Console.WriteLine (i);
      }
   }
}

herbivore
22.02.2006 23:26 E-Mail | Beiträge des Benutzers | zu Buddylist hinzufügen
herbivore
myCSharp.de-Poweruser/ Experte

avatar-2627.gif


Dabei seit: 11.01.2005
Beiträge: 49.478
Entwicklungsumgebung: csc/nmake (nothing is faster)
Herkunft: Berlin


herbivore ist offline

Beitrag: beantworten | zitieren | editieren | melden/löschen       | Top

Hallo zusammen,

eine überarbeitete Version der MetaCollection findet ihr als Iter.Join in  Hilfreiche Iteratoren / Improving Foreach.

herbivore
24.02.2006 11:54 E-Mail | Beiträge des Benutzers | zu Buddylist hinzufügen
Baumstruktur | Brettstruktur       | Top 
myCSharp.de | Forum Der Startbeitrag ist älter als 14 Jahre.
Der letzte Beitrag ist älter als 14 Jahre.
Antwort erstellen


© Copyright 2003-2020 myCSharp.de-Team | Impressum | Datenschutz | Alle Rechte vorbehalten. | Dieses Portal verwendet zum korrekten Betrieb Cookies. 08.08.2020 02:04