Werte fitten/skalieren/anpassen?



  • Hallo,
    ich weiß nichtmal, wie man das nennt, was ich gerne hätte.
    Jedenfalls gibt es zwei Wertebereiche, zB

    A = { 1, 2, 3, 4, 5, 6, 7, 8, 9 }
    B = { 3, 5, 7 }

    Daraus soll sich dann ergeben

    C = { 3, 3, 3, 5, 5, 5, 7, 7, 7 } // Größe von A

    Wie mache ich sowas? A und B sollen beliebig sein, in diesem Fall soll B erstmal nicht größer wie A sein.
    Ich hoffe, ich habe mich einigermaßen verständlich ausgedrückt.


  • Mod

    Spielt der Inhalt von a irgendeine Rolle?



  • Nein, es ist nur die Größe von A entscheidend. Es sollen nur die Werte in B an die Größe von A angepasst werden.


  • Mod

    Sprich: Das Problem ist, ein Ganzzahlinterval der Länge N (=Länge von A) in M möglichst gleich große Unterintervalle (M = Länge von B ) zu unterteilen.

    Ansatz: Grundlänge der Intervalle ist L = N / M (Ganzzahldivision), die Anzahl der Intervalle, die aber Länge L+1 haben müssen ist P = N % M. Die kannst du dann hinlegen, wo du willst. Einfach, aber etwas unschön, wäre es, diese P Intervalle einfach alle an den Anfang zu legen. Wenn du sie lieber gleichmäßig verteilt haben willst, dann sag Bescheid.



  • Dann brauchst du doch nur als Faktor den Quotienten aus der Anzahl von A und Anzahl von B berechnen, also Factor = size(A) / size(B).
    Und dann jeden Wert in B so oft wie Factor wiederholen.

    Bei nicht-ganzzahligem Quotienten mußt du dann selbst entscheiden, was du gerne als Ergebnis hättest.



  • @SeppJ sagte in Werte fitten/skalieren/anpassen?:

    dann sag Bescheid.

    Bescheid



  • Vielen Dank. Ich hab das jetzt so hinbekommen, das ich erst eine neue Menge C erstelle. So war das wohl auch verstanden worden?

    Ich hab das extrem umständlich gelöst, ich schreib das mal als Code

            int sizeA = 11;
    	std::vector<int> B = { 3, 5, 7 };
    	std::vector<int> C;
    
    	int f = sizeA / B.size();
    	int p = sizeA % B.size();
    	std::size_t n = 0;
    
    	for (int i = 0; i < sizeA / f; ++i)
    	{
    		for (int j = 0; j < f; ++j)
    		{
    			C.push_back(B[n]);
    		}
    		++n;
    	}
    	for (int i = 0; i < p; ++i)
    	{
    		C.push_back(B[n-1]);
    	}
    

    Mein Ziel ist es, sofort nur mit der Eingabe eines Index innerhalb von A, den Wert aus C zurück zu geben, ohne erst C zu erstellen..
    Das kann man doch bestimmt direkt berechnen?


  • Mod

    @Swordfish sagte in Werte fitten/skalieren/anpassen?:

    @SeppJ sagte in Werte fitten/skalieren/anpassen?:

    dann sag Bescheid.

    Bescheid

    Wir wollen also P möglichst äquidistant auf ein Ganzzahlintervall der Längen M aufteilen (P < M). Der mittlere Abstand muss dann M / P sein. Dieses Mal keine Ganzzahldivision, denn wir wollen ja gerade auch die Sprünge für ungerade Teilungen ermitteln. Dann müssen wir zwei Sachen mitzählen, unsere Schleife über alle Intervalle M, und nochmal extra einen Counter, wo der nächste Sonderintervall liegt. Immer wenn der Zähler für M größer gleich der Anforderung an ein Sonderintervall ist, dann machen wir eben ein solches Sonderintervall und bestimmen den Ort des nächsten Intervalls. Da P < M ist das stets mindestens das nächste Intervall, es gibt keine doppelt gesonderten Intervalle. In Code ungefähr so:

      int M, P;
      cin >> M >> P;
    
      float hop = 1.* M / P;
      float hop_counter = 0;
    
      for(int i=0; i < M; ++i)
        {
          if (i >= hop_counter)
            {
              cout << 1;  // Dies ist ein langes Intervall
              hop_counter += hop;
            }
          else
            cout << 0;  // Dies ist ein normales Intervall
        }
    

    Dies ist jetzt noch nicht robust gegenüber eventuellen Fließkommaungenauigkeiten. Da ich den hop-Counter bei 0 losgehen lasse, und (double) 0. >= (int) 0 zuverlässig gilt, müssten schon Ungenauigkeiten am Ende sich auf mehr als 1 akkumulieren. Ich denke, den Fall kann ich also vernachlässigen, und obigen Entwurf als Lösung dastehen lassen. Wenn man aber noch ein Offset einbaut, um nicht immer linkslastig zu sein, dann muss man daran denken, dass man da nix falsch macht.


  • Mod

    Um zeropage nicht hängen zu lassen eine Komplettlösung mit allen meinen Vorschlägen vereint:

    #include <iostream>
    #include <string>
    using namespace std;
    
    int main()
    {
      string alphabet;  // Das b
      int total_length ;  // Die Länge von a
    
      cin >> alphabet >> total_length;
    
      int num_intervals = alphabet.size();  // Mein M, die Länge von b, aus meiner ersten Antwort
      int sub_interval_length =  total_length / num_intervals;  // Mein L aus meiner ersten Antwort
      int num_long_intervals = total_length % num_intervals;;  // Mein P aus meiner ersten Antwort
      float hop_step = 1.* num_intervals / num_long_intervals;  // Mein "mittlerer Abstand" aus der zweiten Antwort
    
    
      float hop_counter = 0;
      for(int i=0; i < num_intervals; ++i)  // Durch den Inhalt von b/alphabet gehen. Kein range-based for, weil wir den counter i tatsächlich brauchen
        {
          if (i >= hop_counter)  // Dies muss ein langes Intervall sein
            {
              for(int j=0; j<sub_interval_length+1; ++j)   // langes Intervall heißt um 1 länger als die Normlänge
                cout << alphabet[i];
              hop_counter += hop_step;  // Rechne Position des nächsten langen Intervalls aus
            }
          else   // Dies ist ein normales Intervall
            {
            for(int j=0; j<sub_interval_length; ++j)
              cout << alphabet[i];
            }
        }
      cout << '\n';
    }
    


  • @SeppJ check 👍



  • Super, vielen Dank.


  • Gesperrt

    Dieser Beitrag wurde gelöscht!

Anmelden zum Antworten