Miniprog: Wer liefert schnellstes snippet :) -> anzahl gleicher zahlen in folge



  • Hallo,

    ich versuche gerade eine möglichst schnelle Variante des folgenden Miniproblems zu implementieren:

    Man hat eine gegeben folge von Zahlen in einem Array:

    2,5,3,1,2,2,5,3,1,5,5,5

    Und jetzt will ich in ein ergebnisarray die anzahl an gleichen zahlen aufsteigend.

    Also wenn mans sortiert ist es ja:

    1,1,2,2,2,3,3,5,5,5,5,5

    und das ergebnis sollte sein:

    2,3,2,5

    Die arraygrösse des ergebnisarrays ist vorher bekannt, also es ist bekannt wieviel unterschiedliche zahlen in dem ausgangsarray vorhanden sind.
    🙂



  • Hab gerade keinen Compiler, würd's aber so machen:

    struct counter_copy {
       counter_copy(int* s, int* e, int* p) : start(s), end(s), pos(p) {}
       int* start, end, pos;
       void operator()(int val) { *p = count(start, end, val); ++p; }
    };
    
    int main() {
       int a[] = { 1,1,2,2,2,3,3,5,5,5,5,5 };     // AusgangsArray
       size_t const a_size = sizeof(a)/sizeof(int);
       int werte[a_size];                         // vorhandene Werte
       size_t numElements[a_size];                // Haeufigkeit der Werte
       counter_copy c(a, a+a_size, numElements);  // Zaehler-Funktor
    
       int* werte_end = unique_copy(a, a+a_size, werte);
       for_each(werte, werte_end, c);
       return 0;
    }
    

    Geht aber bestimmt noch kürzer.

    Gruß,

    Simon2.



  • int a[] = { 1,1,2,2,2,3,3,5,5,5,5,5 };
    const int num = sizeof(a)/sizeof(int);
    
    map<int,int> mappo;
    
    for(int i=0; i<num; ++i)
            ++mappo[a[i]];
    

    @Simon: Ich nehms dir net übel 🙂

    Simon2 schrieb:

    Hab gerade keinen Compiler

    ~Anstatt nen neuen Beitrag zu schreiben, editiere ich meine alten 🙄~



  • KasF schrieb:

    ...

    @Simon: Ich nehms dir net übel 🙂

    Simon2 schrieb:

    Hab gerade keinen Compiler

    Ja, hast ja Recht ... meine ursprünglich feste "10" wäre wohl besser gewesen - außerdem ist Deins ja nun wirklich kürzer und eleganter ! Super !

    Gruß,

    Simon2.



  • Mit Hilfe des Compilers nochmal verbessert:

    struct counter_copy {
       counter_copy(int* s, int* e, size_t* p) : start(s), end(e), pos(p) {}
       int *start, *end;
       size_t *pos;
       void operator()(int val) { *pos = count(start, end, val); ++pos; }
    };
    

    Die Methode von mir hatte ich mal von hier aufgeschnappt: http://www.cppreference.com/cppmap/all.html , nur bissl unsauber, da meine Indizes die Zahlen aus dem Array sind und somit jede Menge Stellen in der map leer sind, also 0 ausgegeben werde würde, wenn man durchiteriert. Aber die könnte man ja alle einfach noch entfernen, weiß aber im moment nicht wie ...


  • Mod

    KasF schrieb:

    Die Methode von mir hatte ich mal von hier aufgeschnappt: http://www.cppreference.com/cppmap/all.html , nur bissl unsauber, da meine Indizes die Zahlen aus dem Array sind und somit jede Menge Stellen in der map leer sind, also 0 ausgegeben werde würde, wenn man durchiteriert. Aber die könnte man ja alle einfach noch entfernen, weiß aber im moment nicht wie ...

    Es soll ja ein Ergebnisarray werden, dann können wir kopieren und die Nullen gleichzeitig entfernen:

    std::vector<int> ergebnis;
    remove_copy(mappo.begin(),mappo.end(),back_inserter(ergebnis),0);
    


  • camper schrieb:

    std::vector<int> ergebnis;
    remove_copy(mappo.begin(),mappo.end(),back_inserter(ergebnis),0);
    

    Mit remove etc. bin ich mich ja die ganze Zeit am rumschlagen. Wenn remove den Iterator dereferenziert kommt ja ein pair<> dabei raus und der kann nicht einfach mit 0 verglichen werden. Man könnte das mit Funktionsobjekten etc. ausbauen, damit es funkitoniert, aber wäre keine EinZeilenLösung, so wie es sonst funktioniert: ( Kann sein das ich mich mit dem geschriebenen irren könnte ).

    Komischerweise werden die 0'en nur bei normalen indiziertem iterieren angezeigt nicht wenn ich über Iteratoren gehe:

    for(map<int,int>::iterator it = mappo.begin(); it != mappo.end(); ++it)
        cout << it->second;
    //2325
    
    for(int i=0; i<mappo.size(); ++i)
            cout <<mappo[i];
    //023205
    

    Ein neues Phänomen für mich 🙂


  • Mod

    KasF schrieb:

    Wenn remove den Iterator dereferenziert kommt ja ein pair<> dabei raus und der kann nicht einfach mit 0 verglichen werden.

    Stimmt - hab ich geschlafen.

    KasF schrieb:

    Komischerweise werden die 0'en nur bei normalen indiziertem iterieren angezeigt nicht wenn ich über Iteratoren gehe:

    Ein neues Phänomen für mich 🙂

    Weil mappo[0] erst in deiner Schleife angelegt wird 😉



  • KasF schrieb:

    nur bissl unsauber, da meine Indizes die Zahlen aus dem Array sind und somit jede Menge Stellen in der map leer sind, also 0 ausgegeben werde würde, wenn man durchiteriert.

    Äh, nein. Du musst einfach nur mit den Map-Iteratoren durchgehen, nicht mappo[index] .



  • camper schrieb:

    Weil mappo[0] erst in deiner Schleife angelegt wird 😉

    Ahhhhhhhhh 🙂 (oh man)

    Wieso funktioniert das denn nicht:

    pair<int,int> eraser(0,0);
    remove_copy(mappo.begin(),mappo.end(),back_inserter(ergebnis),eraser);
    

    Macht zwar keinen Sinn, da ja beide Paar-Objekte gleich sein müssen, aber trotzdem.

    stl_algo:remove_copy(...)
    if (!(*__first == __value))
    /*
    error: no match for 'operator==' in '(&__first)->std::_Rb_tree_iterator<_Tp>::operator* [with _Tp = std::pair<const int, int>]() == __value'
    */
    

    😕
    Liefert *__first kein pair<int,int> zurück ?

    Edit: Ja finix, der Groschen ist soeben gefallen.



  • camper schrieb:

    Es soll ja ein Ergebnisarray werden, dann können wir kopieren und die Nullen gleichzeitig entfernen:

    std::vector<int> ergebnis;
    remove_copy(mappo.begin(),mappo.end(),back_inserter(ergebnis),0);
    

    Wie wär's mit

    std::vector<int> result(result_size); // result_size laut Aufgabenstellung bekannt
    transform(mappo.begin(),
              mappo.end(),
              result.begin(), // edit: statt c&p-Fehler "back_inserter(result)",
              select2nd<map<int, int>::value_type>());
    

    Edit:

    KasF schrieb:

    Edit: Ja finix, der Groschen ist soeben gefallen.

    Hehe, ja ich seh's. Sollte mir echt angewöhnen meine Tabs hin und wieder zu refreshen 😞



  • Die Anzahl gleicher Zahlen (Thread Text) oder gleicher Zahlen in Folge (Thread Titel)?
    Die Anzahl gleicher Zahlen in Folge ist trivial und geht ungefähr so:

    void lala(int const* in, size_t size, int* out)
    {
        for (size_t i = 1; i < size; i++)
        {
            (*out)++;
            if (in[i] != in[i-1])
                out++;
        }
    }
    


  • @hustbaer: da stimmt noch was mim letzten index nicht....also bei der berechnung der letzten gleichen zahlen....ich schau gerade...



  • hustbaer hat halt vorher nicht sortiert 🤡



  • 😕 WAS?

    dann gehts doch erste recht nicht ...oder bin ich jetzt shcon ganz blind vor bäumen



  • achso.....er meint die anzahl gleicher zahlen in FOLGE....
    also sowas: 223322244 wäre 2232

    ich aber brauche halt: 522 weil 5 2er auftauchen 🙂



  • Das kürzeste was ich vom Code her hinbekomme, sieht so aus:

    void lala(int const* in, size_t size, int* out)
    {
        std::map<int,int> vals;
        for ( size_t i=0; i<size; i++ )
            ++ vals[ in[i] ];
        for ( map<int,int>::iterator iter=vals.begin(); iter!=vals.end(); iter++ )
            *(out++) = iter->second;
    }
    


  • also die version von hustbaer hat halt am ende des arrays ein problem weil er ja dann zu wenig zählt...ohne jetzt vorlaut sein zu wollen...

    Ich danke euch allen - aber ich wollte eigentlich nicht die Kürzeste version - sonder die schnellste 🙂

    aber scheint wohl einher zu gehen....



  • @badestrand...du sortierst vorher nicht nicht wahr?

    ich revidiere gerade die aussage von vorhin dass das von hustbaer nicht stimmt....mein hirn nimmts als korrekt an - nur mein eingabe array zählt am ende zu wenig....ich muss noch mal drüberschauen 🙄 🙄



  • gast_xy schrieb:

    @badestrand...du sortierst vorher nicht nicht wahr?

    std::map sortiert automatisch, hab ich mir einfach zu eigen gemacht ...

    btw, hier meine "schnelle, aber lange" Version:

    void lala( int const* in, size_t in_size, int* out, size_t out_size )
    {
    	struct Duo
    	{
    		int key;
    		int value;
    
    		static void SwapElements( Duo* list, int first, int second )
    		{
    			Duo tmp = list[first];
    			list[first] = list[second];
    			list[second] = tmp;
    		}
    
    		static void Quicksort( int low, int high, Duo* list )
    		{
    			int top = low;
    			int bottom = high - 1;
    			int iPartitionIndex = 0;
    			int iPartitionValue = 0;
    			if ( low < high )
    			{
    				if ( high == (low+1) )
    				{
    					if ( list[low].key >= list[high].key )
    						SwapElements( list, high, low );
    				}
    				else
    				{
    					iPartitionIndex = static_cast<int>((low + high) / 2);
    					iPartitionValue = list[iPartitionIndex].key;
    					SwapElements( list, high, iPartitionIndex );
    					do
    					{
    						while ( (list[top].key<iPartitionValue) && (top<=bottom) )
    							++top;
    						while ( (list[bottom].key>=iPartitionValue) && (top <= bottom))
    							--bottom;
    						if ( top < bottom )
    							SwapElements( list, top, bottom );
    					} while ( top < bottom );
    					SwapElements( list, top, high );
    					Quicksort( low, top-1, list );
    					Quicksort( top+1, high, list );
    				}
    			}
    		}
    	};
    
    	int n = 0;
    	Duo* m = new Duo [ out_size ];
    
    	for ( size_t i=0; i<in_size; ++i )
    	{
    		bool found = false;
    		for ( int j=0; j<n; j++ )
    		{
    			if ( m[j].key == in[i] )
    			{
    				++m[j].value;
    				found = true;
    				break;
    			}
    		}
    		if ( ! found )
    		{
    			m[n].key = in[i];
    			m[n].value = 1;
    			++n;
    		}
    	}
    
    	Duo::Quicksort( 0, n-1, m );
    
    	for ( int i=0; i<n; ++i )
    		out[i] = m[i].value;
    
    	delete[] m;
    }
    

Anmelden zum Antworten