Pracuję nad tabelą 2D z STD :: Map (), aby policzyć, ile razy jedno przejścia na inny numer. Wpadłem na dwa problemy. Po pierwsze, moje pierwsze przejście nie pokazuje (1-> 2). Po drugie, wszystkie moje przejścia znajdują się tylko raz (2-> 3 i 3-> 1 dwa razy).

Widzę, dlaczego przejścia dzieje się tylko raz. Iterator nie widzi currentval i idzie, gdzie dodaje wartości, a następnie wychodzi. Nie jestem pewien, jak to jednak naprawić. Każda pomoc jest doceniana!

#include <iostream>
#include <map>
#include <algorithm>
#include <vector>

using namespace std;

//import midi notes
vector <int> midiFile = {1, 2, 3, 1, 20, 5, 2, 3, 1};

//create a 2d hashmap for matrix
map <string, map <string, int> > mCounts;

//strings for the previous value and current value
string prevVal = "";
string currentVal = "";

void addNumbers(vector <int> midiFile) {

    for (int i = 0; i < midiFile.size(); i++) {
        currentVal = to_string(midiFile[i]);

        if(prevVal == "") {
            prevVal = currentVal;   //first value
        } else {
            //playCounts is temporary map to store counts of current val in relation to previous val
            map <string, int> playCounts;

            map <string, int> ::iterator iterator;
            iterator = playCounts.find(currentVal);

            //if mCounts doesn't contain the value yet, create a new hashmap
            if(iterator != playCounts.end()){

                int counter = iterator -> second;
                mCounts[prevVal] [currentVal] = counter + 1;


            } else {
                playCounts.insert(pair <string, int>(currentVal, 1));
                mCounts [prevVal] = playCounts;

            }

            prevVal = currentVal;

        }

        //find values already in map
        map <string, map <string, int> > ::iterator it;
        it = mCounts.find(prevVal);

        if (it != mCounts.end()) {
            //if value is found, do nothing
        } else {
            mCounts.insert(pair <string, map <string, int>>(prevVal, map <string, int>()));
        }
    }
}
0
Joshua Hodge 28 marzec 2017, 22:38

3 odpowiedzi

Najlepsza odpowiedź

Masz do czynienia z małymi liczbami całkowitymi 128. Po prostu użyj macierzy, gdzie transition[i][j] jest liczbą przejść od I do jotów. Zwykle zalecam płaski bufor do matryc z indeksu mnożenia, aby uzyskać dostęp do wymiaru 2D lub przedwczesnego opakowania klasowego wokół tego samego (patrz Eigen). Ale w tym przypadku matryca jest tak mała, możesz po prostu użyć

int transition[128][128];

Oczywiście chcesz wpisać to i przekazać go przez odniesienie. Nie tylko wszystkie twoje operacje będą łatwiejsze i bardziej przejrzyste, ale przy użyciu matrycy przejściowej przyznaje analizę, która nie jest możliwa w inny sposób: EIGENVECTORS dla stanów równowagi itp.

W przypadku większych problemów, w których przejścia są rzadkie i nie możesz sobie pozwolić na gęstą matrycę, użyj rzeczywistej klasy rzadkiej matrycy, co jest zasadniczo, co próbujesz się przewrócić.

typedef int transitionMatrix[128][128];

void addNumbers(const vector <int> &midiFile, transitionMatrix &mCounts) {
    for (int i = 0; i < midiFile.size()-1; i++) {
        int prev = midiFile[i];
        int curr = midiFile[i+1];
        mCounts[prev][curr]++;
    }
}
0
Peter 29 marzec 2017, 13:52

Wypróbuj następujące podejście, w którym dwa liczby całkowite tworzące przejście są połączone z pojedynczym ciągiem formularza "1->2", który następnie służy jako klawisz na mapie liczenia. Kodeks staje się bardziej zwięzły. Ponadto wyeliminowałem zmienne globalne i sprawiłem, że lokalne lub parametry:

#include <iostream>
#include <map>
#include <vector>
#include <sstream>

using std::vector;
using std::map;
using std::string;

void addNumbers(const vector <int> &midiFile, map <string, int> &mCounts) {

    for (int i = 0; i < midiFile.size()-1; i++) {

        int prev = midiFile[i];
        int curr = midiFile[i+1];
        std::stringstream ss;
        ss << prev << "->" << curr;

        mCounts[ss.str()]++;
    }
}


int main(int argc, char* argv[])
{
    vector <int> midiFile = {1, 2, 3, 1, 20, 5, 2, 3, 1};
    map <string, int> mCounts;

    addNumbers(midiFile, mCounts);
    for (auto const& x : mCounts)
    {
        std::cout << x.first  // transition
        << ':'
        << x.second // count
        << std::endl ;
    }

    return 0;
}

Wynik:

1->2:1
1->20:1
2->3:2
20->5:1
3->1:2
5->2:1
0
Stephan Lechner 28 marzec 2017, 22:05

Oto rozwiązanie, które nie używa zagnieżdżonych map i nie konwertuje uwagi do ciągów (ale zakłada, że uwagi są nienegiery):

// This snippet uses c++11 syntax
#include <map>

// Code in this example assumes that valid notes are nonnegative
struct transition {
    int from;
    int to;
};

// Comparison operator required to make transition usable as a
// key in std::map
bool operator< (const transition& l, const transition& r) {
    return l.from < r.from || (l.from == r.from && l.to < r.to);
}

// Range of all transitions with respective counter
// starting from a particular note 
std::pair<std::map<transition, int>::const_iterator,
    std::map<transition, int>::const_iterator>
transitions_from(int from_note,
        const std::map<transition, int>& transition_counters) {
    return std::make_pair(transition_counters.lower_bound(transition{from_note, -1}),
            transition_counters.upper_bound(transition{from_note + 1, -1}));
}

int counter_for(transition t, const std::map<transition, int>& transition_counters) {
    const auto it = transition_counters.find(t);
    if (it != transition_counters.end()) {
        return it->second;
    } else {
        return 0;
    }
}

Przykład użycia:

#include <iostream>
#include <vector>

int main() {
    std::vector<int> notes = {1, 2, 3, 1, 20, 5, 2, 3, 1};
    std::map<transition, int> transition_counters;
    int previous_note = -1;
    for (int note: notes) {
        if (previous_note != -1) {
            transition t{previous_note, note};
            transition_counters[t] += 1;
        }
        previous_note = note;
    }

    std::cout << "all encountered transitions:\n";
    for (const auto& entry: transition_counters) {
        std::cout << '(' << entry.first.from << " -> " << entry.first.to << "): " << entry.second << '\n';
    }

    std::cout << "transitions from 1:\n";
    const auto transitions_from_1 = transitions_from(1, transition_counters);
    for (auto it = transitions_from_1.first; it != transitions_from_1.second; ++it) {
        std::cout << '(' << it->first.from << " -> " << it->first.to << "): " << it->second << '\n';
    }

    std::cout << "counters for individual transitions:\n";
    std::cout << "(1 -> 2): " << counter_for(transition{1, 2}, transition_counters) << '\n';
    std::cout << "(2 -> 1): " << counter_for(transition{2, 1}, transition_counters) << '\n';
}
0
Grisha 29 marzec 2017, 12:20