Doppelte Kombinationen auflisten (C ++) → Python-Code hinzufügen

** Aktualisiert am 14.9.: Das im Kommentarbereich beschriebene Implementierungsbeispiel finden Sie am Ende dieses Artikels. (C ++, Python) **

Artikelübersicht

Ich wollte eine Kombination erstellen, die eine Duplizierung in C ++ ermöglicht, an die ich nicht gewöhnt bin. Deshalb habe ich viel gesucht, aber ich konnte sie nicht leicht finden. Es gibt eine "Reihenfolge", die Duplikate zulässt, und eine Formel, die die Gesamtzahl der Duplikatkombinationen berechnet ($ \ small_n H_r $, die ich in der Junior High School gelernt habe), aber der Code, der Duplikatkombinationen aufzählen kann, wurde nicht umgedreht. Wenn ich es nachgeschlagen habe, scheint es, dass es in Python und so weiter normalerweise in "itertools" als Funktion namens "kombination_mit_replacement ()" enthalten ist, so dass Code (https://docs.python.org/ja/3/library/itertools.html) ) Und erneut in C ++ implementiert. Wenn Sie Fehler oder Verbesserungen haben, teilen Sie uns dies bitte mit.

Algorithmusfluss

Betrachten Sie zunächst als Beispiel eine Kombinationsaufzählung, wenn Sie $ 2 $ -Elemente aus der Menge $ \ left \ {1, 2, 3 \ right \} $ extrahieren, um eine Duplizierung zu ermöglichen. Der Ablauf selbst ist einfach und sieht folgendermaßen aus:

  1. Bereiten Sie $ 2 $ Paare von $ \ left \ {1, 2, 3 \ right \} $ vor und suchen Sie das kartesische Produkt (direktes Produktset). $ (1, 1), (1, 2), (1, 3), (2, 1), (2, 2), (2, 3), (3, 1), (3, 2), (3, 3) $
  2. Extrahieren Sie eine einzigartige Kombination aus dem kartesischen Produkt. $ (1, 1), (1, 2), (1, 3), (2, 2), (2, 3), (3, 3) $

Mit anderen Worten, wenn Sie im Allgemeinen eine Duplizierung aus der Menge $ \ Omega $ zulassen und $ n $ Elemente extrahieren möchten, können Sie $ \ Omega $ in $ n $ duplizieren und eine eindeutige Kombination aus ihrem kartesischen Produkt extrahieren. Es wird sein.

Erzeugung eines kartesischen Produkts

Implementieren Sie zunächst das kartesische Produkt. Es scheint, dass es in Python auch eine Funktion namens "product ()" von "itertools" gibt, aber ich konnte die Doppellisten-Einschlussnotation im Quellcode nicht einholen, also habe ich das kartesische Produkt in Golang implementiert. Ich habe auf den Code der Person verwiesen, die ist (https://qiita.com/tesujiro/items/2e41e1159948dc90c3d9). Diese Person schreibt im Allgemeinen den Code, um das kartesische Produkt zwischen mehreren Sätzen von $ \ Omega_1, \ Omega_2, \ Omega_3, \ ldots $ zu berechnen.

In meiner Implementierung dieses Mal "Duplikate aus $ \ Omega $ zulassen und $ n $ Teile extrahieren", also $ \ Omega_1 = \ Omega, \ Omega_2 = \ Omega, \ Omega_3 = im Allgemeinen kartesisches Produkt Entspricht \ Omega, \ ldots, \ Omega_n = \ Omega $. Wenn der Wert von $ n $ zunimmt, wird es schwierig, $ \ Omega $ um die Anzahl von $ n $ zu duplizieren und dem Argument zuzuweisen, sodass $ n $ mit dem Argument repeat gezählt wird. Ich werde. Zunächst wird der Code unten veröffentlicht.

python


#include <bits/stdc++.h>
using namespace std;

template<typename T>
vector<vector<T>> productRecurse(vector<T>, int, vector<vector<T>>);

//kartesisches Produkt
template<typename T>
vector<vector<T>> product(vector<T> choices, int repeat) {
    vector<vector<T>> emptyResult(1, vector<T>());//Leere Liste zum Speichern von Kombinationen

    return productRecurse(choices, repeat, emptyResult);
}

template<typename T>
vector<vector<T>> productRecurse(vector<T> choices, int repeat, vector<vector<T>> result) {
    if (repeat == 0) {return result;}//Geben Sie die Antwort zurück, wenn das kartesische Produkt fertig ist
    
    vector<vector<T>> provisionalResult;//Kartesisches Produkt im Entstehungsprozess
    
    for (vector<T> re: result) {
        for (T c: choices) {
            vector<T> temp = re;
            temp.push_back(c);
            provisionalResult.push_back(temp);
        }
    }
    
    return productRecurse(choices, repeat - 1, provisionalResult);
}

Betrachten wir zur Erläuterung des obigen Codes noch einmal ein Beispiel, um die Menge $ \ left \ {1, 2, 3 \ right \} $ in $ 2 $ zu duplizieren und ein kartesisches Produkt zu erstellen. Der Ablauf beim Aufrufen von "Produkt (Auswahl = {1, 2, 3}, Wiederholung = 2)" ist wie folgt.

  1. Rufen Sie "Produkt (Auswahl = {1, 2, 3}, Wiederholung = 2)" auf.
  2. productRecurse (Auswahl = {1, 2, 3}, Wiederholung = 2, Ergebnis = {{}}) wird aufgerufen.
  3. provisorisches Ergebnis = {{1}, {2}, {3}}.
  4. productRecurse (Auswahl = {1, 2, 3}, Wiederholung = 1, Ergebnis = {{1}, {2}, {3}}) wird aufgerufen.
  5. provisorisches Ergebnis = {{1, 1}, {1, 2}, {1, 3}, {2, 1}, {2, 2}, {2, 3}, {3, 1}, {3 , 2}, {3, 3}} .
  6. productRecurse (Auswahl = {1, 2, 3}, Wiederholung = 0, Ergebnis = {{1, 1}, {1, 2}, {1, 3}, {2, 1}, {2, 2 }, {2, 3}, {3, 1}, {3, 2}, {3, 3}}) wird aufgerufen.
  7. Da repeat == 0 ist das Argument result das endgültige kartesische Produkt.

In Python bedeutet dies, dass der Teil, der in die Liste aufgenommen werden kann, rekursiv wiederholt wird. Lassen Sie es uns tatsächlich ausführen.

python


int main(){
    vector<int> choices = {1, 2, 3};
    int repeat = 2;
    
    vector<vector<int>> answer = product(choices, repeat);
    
    for (int i = 0; i < answer.size(); i++) {
        cout << answer[i][0] << " " << answer[i][1] << endl;
    }
}

Wie manuell berechnet, können Sie sehen, dass die kartesischen Produkte korrekt aufgelistet sind.

1 1
1 2
1 3
2 1
2 2
2 3
3 1
3 2
3 3

Extraktion von Doppelkombinationen

Nun, sobald Sie hier sind, ist der Rest einfach. Extrahieren Sie eine einzigartige Kombination aus dem kartesischen Produkt. Kurz gesagt, wenn Sie beispielsweise $ (1, 2) $ extrahieren, reicht es aus, $ (2, 1) $ auszuschließen. Für eine bestimmte Kombination "Kamm" werden also nur diejenigen mit "Kamm == sort (Kamm)" extrahiert. Machen.

python


template<typename T>
vector<vector<T>> combWithReplace(vector<T> choices, int n) {
    vector<vector<T>> answer;
    
    for (vector<T> comb: product(choices, n)) {
        vector<T> toSorted = comb;
        sort(toSorted.begin(), toSorted.end());
        if (comb == toSorted) {
            answer.push_back(comb);
        }
    }
    return answer;
}

Ausführungsergebnis

Jetzt ist das Programm zum Auflisten der doppelten Kombinationen abgeschlossen. Versuchen Sie abschließend erneut eine Kombinationsaufzählung, um Duplikate aus der Menge $ \ left \ {1, 2, 3 \ right \} $ zuzulassen und $ 2 $ -Elemente zu extrahieren.

python


int main(){
    vector<int> choices = {1, 2, 3};
    int n = 2;
    
    vector<vector<int>> answer = combWithReplace(choices, n);
    
    for (int i = 0; i < answer.size(); i++) {
        cout << answer[i][0] << " " << answer[i][1] << endl;
    }
}

Das Ergebnis ist wie folgt. Sie können sehen, dass das gleiche Ergebnis wie bei der manuellen Berechnung erzielt wird. Sie können auch sehen, dass jede Kombination auch sortiert ist.

1 1
1 2
1 3
2 2
2 3
3 3

Am Ende

Beim Betrachten des Quellcodes für Pythonitertools hätte ich nie gedacht, dass die Implementierung von c ++ so mühsam sein würde. Es gab einen Grund, warum die Listeneinschlussnotation existierte, obwohl sie weniger lesbar war. $ \ Ldots $. Wenn Sie Fehler haben, lassen Sie es uns bitte wissen. Vielen Dank für das Lesen bis zum Ende.

Verweise

  1. https://docs.python.org/ja/3/library/itertools.html
  2. https://qiita.com/tesujiro/items/2e41e1159948dc90c3d9

Nachtrag (9/14)

Das Folgende ist ein Implementierungsbeispiel, das von @Nabetani gelehrt wird. Bitte beachten Sie den Kommentarbereich für die Leistung usw.

Meine Implementierung steht im Einklang {{}} ⇒{{1}, {2}, {3}} ⇒{{1, 1}, {1, 2}, {1, 3}, {2, 1}, {2, 2}, {2, 3}, {3, 1}, {3, 2}, {3, 3}} Während die entsprechenden Elemente nach Fertigstellung des kartesischen Produkts extrahiert wurden, wird in dieser Implementierung jede Kombination verwendet.

{} ⇒ {1} ⇒ {1, 1} ⇒ Zur Antwort hinzufügen ⇒ {1, 2} ⇒ Zur Antwort hinzufügen ⇒ {1, 3} ⇒ Zur Antwort hinzufügen {} ⇒ {2} ⇒ {2, 2} ⇒ Zur Antwort hinzufügen ⇒ {2, 3} ⇒ Hinzufügen, um $ \ cdots $ zu beantworten

Es scheint, dass es in Form von vervollständigt und der Antwort hinzugefügt wird. (Append () Funktion in der Struktur) Dies ist möglicherweise leichter zu verstehen, da es der Operation zum Aufzählen doppelter Kombinationen durch manuelle Berechnung ähnelt.

c++14


#include <iterator>
#include <vector>

template <typename container_type>
std::vector<std::vector<typename container_type::value_type>>
combWithReplace(container_type const &choices, size_t n) {
  using value_type = typename container_type::value_type;
  using selected_t = std::vector<value_type>;
  using itor_t = typename container_type::const_iterator;
  struct impl { //Rekursion ist mit Lambda problematisch, machen Sie es also zu einer Klasse
    std::vector<std::vector<value_type>> &r_; //Haben Sie einen Verweis, um das Kopieren zu vermeiden
    impl(std::vector<std::vector<value_type>> &r) : r_(r) {}
    void append(selected_t &s, itor_t b, itor_t e, size_t n) {
      if (n == 0) {
        r_.push_back(s);
      } else {
        for (auto it = b; it != e; ++it) {
          s.push_back(*it);
          append(s, it, e, n - 1);
          s.pop_back();
        }
      }
    };
  };
  std::vector<std::vector<value_type>> r;
  impl o{r};
  selected_t e;
  e.reserve(n);
  o.append(e, std::cbegin(choices), std::cend(choices), n);
  return r;
}

python3.8



def comb_with_replace(a, n):
    r = []

    def append(e, b, add_count):
        """Zählen Sie die Elemente doppelter Kombinationen mit rekursiv auf und fügen Sie die gefundenen Kombinationen zu r hinzu

        Parameters
        ----------
        e : list
Doppelte Kombination in der Mitte der Montage
        b : int
Index am Anfang der verfügbaren Elemente
        add_count : int
Anzahl der Elemente, die zu e hinzugefügt werden sollen
        """
        if add_count == 0:
            r.append(e)
        else:
            for ix in range(b, len(a)):
                append(e+[a[ix]], ix, add_count-1)
    append([], 0, n)
    return r


def main():
    choices = [1, 2, 3]
    for e in comb_with_replace(choices, 2):
        print(e)


main()

Recommended Posts

Doppelte Kombinationen auflisten (C ++) → Python-Code hinzufügen
Führen Sie Python-Code über die C # -GUI aus
Python-Aufzählungsfunktion
Python-Zeichencode
Python C ++ Notizen
Python, openFrameworks (c ++)
[Python] Code, der Algorithmen kennt
Ich möchte C ++ - Code aus Python-Code erstellen!
Ich hatte das Gefühl, dass ich den Python-Code nach C ++ 98 portiert habe.
[Python] Operation der Aufzählung
Python C / C ++ - Erweiterungsmusterzeiger
Schreiben Sie Python2-Code in Python3 um (2to3)
Vor dem Schreiben von Python-Code
Weiter Python in C-Sprache
C-API in Python 3
ABC147 C --HonestOrUnkind2 [Python]
Python Fordert den Statuscode an
Hierarchie, Reihenfolge, (doppelte) Kombination in Python / Ruby / PHP / Golang (Go)