C++ 中的二维迭代器访问
2D iterator access in C++
我正在使用 std::map() 开发二维 table 来计算一个数字转换为另一个数字的次数。我 运行 有两个问题。首先,我的第一个转换没有显示 (1->2)。其次,我所有的转换都只显示一次(2->3 和 3->1 都发生了两次)。
我明白为什么转换只发生一次了。迭代器看不到 currentVal 并转到 else,在其中添加值然后退出。我不确定如何解决这个问题。感谢您的帮助!
#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>()));
}
}
}
尝试以下方法,其中构成转换的两个整数组合成 "1->2"
形式的单个字符串,然后用作计数映射中的键。这样代码就变得更简洁了。此外,我删除了全局变量并使它们成为局部变量或参数:
#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;
}
输出:
1->2:1
1->20:1
2->3:2
20->5:1
3->1:2
5->2:1
这是不使用嵌套映射且不将音符转换为字符串的解决方案(但假定音符是非负数):
// 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;
}
}
用法示例:
#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';
}
您正在处理小于 128 的小整数。只需使用一个矩阵,其中 transition[i][j]
是从 i 到 j 的转换次数。通常,我建议为具有索引乘法的矩阵使用平面缓冲区以访问 2d 维度,或者使用预先编写的 class 包装相同的东西(参见 Eigen)。但是在这种情况下,矩阵很小,你可以使用
int transition[128][128];
你当然想输入定义并通过引用传递它。
不仅您的所有操作都将变得更容易和更透明,而且使用转换矩阵可以进行其他任何方式都不可能进行的分析:平衡状态的特征向量等。
对于过渡稀疏且您负担不起密集矩阵的较大问题,请使用实际的稀疏矩阵 class,这实际上就是您要自己动手做的。
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]++;
}
}
我正在使用 std::map() 开发二维 table 来计算一个数字转换为另一个数字的次数。我 运行 有两个问题。首先,我的第一个转换没有显示 (1->2)。其次,我所有的转换都只显示一次(2->3 和 3->1 都发生了两次)。
我明白为什么转换只发生一次了。迭代器看不到 currentVal 并转到 else,在其中添加值然后退出。我不确定如何解决这个问题。感谢您的帮助!
#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>()));
}
}
}
尝试以下方法,其中构成转换的两个整数组合成 "1->2"
形式的单个字符串,然后用作计数映射中的键。这样代码就变得更简洁了。此外,我删除了全局变量并使它们成为局部变量或参数:
#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;
}
输出:
1->2:1
1->20:1
2->3:2
20->5:1
3->1:2
5->2:1
这是不使用嵌套映射且不将音符转换为字符串的解决方案(但假定音符是非负数):
// 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;
}
}
用法示例:
#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';
}
您正在处理小于 128 的小整数。只需使用一个矩阵,其中 transition[i][j]
是从 i 到 j 的转换次数。通常,我建议为具有索引乘法的矩阵使用平面缓冲区以访问 2d 维度,或者使用预先编写的 class 包装相同的东西(参见 Eigen)。但是在这种情况下,矩阵很小,你可以使用
int transition[128][128];
你当然想输入定义并通过引用传递它。 不仅您的所有操作都将变得更容易和更透明,而且使用转换矩阵可以进行其他任何方式都不可能进行的分析:平衡状态的特征向量等。
对于过渡稀疏且您负担不起密集矩阵的较大问题,请使用实际的稀疏矩阵 class,这实际上就是您要自己动手做的。
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]++;
}
}