Vector nach bestimmten kritieren filtern



  • Hallo,

    ich habe ein Vector, der Artikelobjekte enthält.

    Gibt es eine Möglichkeit, aus dem Vector heraus die Elemente zu selektieren, die die gleiche Artikelnummber haben?

    Ich will meinem Vector sagen: Filtere mir mal die Elemente, die die gleiche Artikelnummer haben.

    Ist es möglich?



  • Was soll denn das Ergebnis sein? Ein neuer Vektor mit den gesuchten Elementen?
    So z.B.

    //Die Artikel-Klasse
    class articles
    {
    
        //...
        item_id_type item_id() const;
        //...
    };
    
    //Praedikat fuer find_if nach Artikelnummer
    struct article_by_item_id
    {
        article_by_item_id(item_id_type id) : m_id(id){}
    
        bool operator()(articles const & a) const
        {
            return m_id == a.item_id();
        }
    
        item_id_type m_id;
    }
    
    //Vektor mit Artikelobjekten
    std::vector<articles> article_list;
    
    //Vektor irgendwie befuellen
    
    //Vektor mit Suchergebnissen
    std::vector<articles> filtered_list;
    
    std::vector<articles>::const_iterator i = article_list.begin();
    
    //Suchen
    while(i != article_list.end())
    {
        i = std::find_if(i, article_list.end(), article_by_item_id(some_id));
        if(i != article_list.end())
        {
            filtered_list.push_back(*i);
            ++i;
        }
    }
    


  • goldenBoy schrieb:

    Ich will meinem Vector sagen: Filtere mir mal die Elemente, die die gleiche Artikelnummer haben.

    1. Gleiche Artikelnummer wie was? Willst du eine Artikelnummer vorgeben?
      Stell dir einen vector vor, in dem 3 Artikel die Nummer 1 haben und 2 Artikel die Nummer 2. "Filtere mir die Elemente, die die gleiche Artikelnummer haben" hieße, dass die 3 mit Nr1 UND die beiden mit Nr2 "gefiltert" werden - weil sie jeweils die gleiche Artikelnummer haben.
    2. Defniere "filtern". Willst du genau die mit der gleichen Artikelnummer anzeigen? oder rauswerfen? oder nur einen drin lassen?


  • Tachyon schrieb:

    ...

    Gerade habe ich mir gedacht, den letzten Teil könnten man auch mit copy_if machen und dann sehe ich, dass es das gar nicht im Standard gibt 😕
    Edit: MSVS hats natürlich 🙂 http://msdn.microsoft.com/en-us/library/ee384415.aspx



  • KasF schrieb:

    Tachyon schrieb:

    ...

    Gerade habe ich mir gedacht, den letzten Teil könnten man auch mit copy_if machen und dann sehe ich, dass es das gar nicht im Standard gibt 😕
    Edit: MSVS hats natürlich 🙂 http://msdn.microsoft.com/en-us/library/ee384415.aspx

    Haben manche Compiler als Erweiterung und kommt im nächsten Standard. Ist aber gar nicht so einfach damit, weil man beim ersten Artiekl noch nciht weiß, ob es andere mit der gleichen Nummer gibt.

    struct Artikel
    {
        std::string Artikelnummer;
    };
    std::ostream& operator<<(std::ostream& os, const Artikel& a)
    {
        return os << a.Artikelnummer;
    }
    
    int main()
    {
        using namespace std;
        vector<Artikel> artikel(5);
        artikel[0].Artikelnummer ="12345";
        artikel[1].Artikelnummer ="13334";
        artikel[2].Artikelnummer ="12334";
        artikel[3].Artikelnummer ="12345";
        artikel[4].Artikelnummer ="13334";
    
        copy(artikel.begin(), artikel.end(), ostream_iterator<Artikel>(cout, "\n"));
        auto compare = [](const Artikel& l, const Artikel& r)->bool
            {return l.Artikelnummer < r.Artikelnummer;};
    
        sort(artikel.begin(), artikel.end(), compare);
    
        vector<Artikel> filter;
        for(auto range = equal_range(artikel.begin(), artikel.end(), artikel.front(), compare);;
            range = equal_range(range.second, artikel.end(), *range.second, compare))
        {
            if (distance(range.first, range.second) > 1)
                copy(range.first, range.second, back_inserter(filter));
            if (range.second == artikel.end())
                break;
        }
        cout << " Filter:\n";
        copy(filter.begin(), filter.end(), ostream_iterator<Artikel>(cout, "\n"));
        return 0;
    } 
    }
    


  • pumuckl schrieb:

    goldenBoy schrieb:

    Ich will meinem Vector sagen: Filtere mir mal die Elemente, die die gleiche Artikelnummer haben.

    1. Gleiche Artikelnummer wie was? Willst du eine Artikelnummer vorgeben?
      Stell dir einen vector vor, in dem 3 Artikel die Nummer 1 haben und 2 Artikel die Nummer 2. "Filtere mir die Elemente, die die gleiche Artikelnummer haben" hieße, dass die 3 mit Nr1 UND die beiden mit Nr2 "gefiltert" werden - weil sie jeweils die gleiche Artikelnummer haben.
    2. Defniere "filtern". Willst du genau die mit der gleichen Artikelnummer anzeigen? oder rauswerfen? oder nur einen drin lassen?

    genauso wie du geschildert hast. Die Ergebnisse möchte ich dann in einem anderen Vektor speichern.

    @Tachyon: ungefähr so habe ich mir das vorgestellt. Muss mir aber erstmal aneignen, wie Prädikate funktionieren.



  • Wenn du am Ende von jeder Artikelnummer nur noch ein Element haben willst, hilft dir unique oder unique_copy .



  • KasF schrieb:

    Gerade habe ich mir gedacht, den letzten Teil könnten man auch mit copy_if machen und dann sehe ich, dass es das gar nicht im Standard gibt 😕

    Momentan gibts std::remove_copy_if() , das Elemente nicht kopiert, auf die eine Bedingung zutrifft. Meiner Meinung nach wäre std::copy_if_not() ein besserer Name dafür gewesen. Und natürlich brauchts den viel häufigeren Fall ohne Negation, nämlich std::copy_if() . Zum Glück kommt das jetzt auch.



  • Nexus schrieb:

    ...Meiner Meinung nach wäre std::copy_if_not() ein besserer Name dafür gewesen...

    Ist das nicht eher std::copy_not_if ? 🤡 Ne, passt schon. Aber der Name ist echt schlecht gewählt.



  • Zuerst kommt normalerweise die Operation und dann ein Anhängsel. "copy_not_if" klingt so, als wäre es eine Variante von "copy_not", und was soll so ein Algorithmus tun? 😉

    Eigentlich brauchts sowas ohnehin nicht, wenn man copy_if hat. Ich meine, find_if oder count_if haben auch keine separate Überladung für negative Prädikate. Dazu kann man Kapselfunktoren benutzen, teilweise ist ja sogar der operator! überladen.

    Der STL-Algorithmus remove_copy_if wurde wahrscheinlich so genannt, weil es auch ein remove_copy gibt (kopiere ausser bei Gleichheit mit bestimmtem Wert). So gesehen sind die beiden lediglich Varianten der Inplace-Algorithmen remove und remove_if , was dann wieder Sinn ergibt. Nur ist es ein wenig inkonsistent mit copy_if ... Naja 🙂



  • goldenBoy schrieb:

    genauso wie du geschildert hast. Die Ergebnisse möchte ich dann in einem anderen Vektor speichern.

    Also alle Elemente, deren Artikelnummer mehrfach vorkommt, in einen anderen vector? Ich würds in 2 Schritten machen:

    1. Zähle zu jeder ArtNr die Elemente
    2. Kopiere alle Elemtente, beideren ArtNr mehr als einer gezählt wurde.

    in C++0x

    class article
    {
        //...
        item_id_type item_id() const;
        //...
    };
    
    std::vector<article> getArticlesWithCommonId(std::vector<article> const& articles)
    {
      std::map<article::item_id_type, unsigned int> counts;
      for(article& : articles)
        ++(counts[article.item_id()]); //schritt 1)
    
      std::vector<article> withCommonId;
      std::copy_if(articles.begin(), articles.end(),
                   std::back_inserter(withCommonId), 
                   [&](article const& a)
                   {
                     return counts[a.item_id()] > 1;
                   });  //schritt 2)
    
      return withCommonId;
    }
    

    Ausprobiert hier:
    http://ideone.com/f658y


Anmelden zum Antworten