我有以下字符串数组:
std::string names_str[7] = {"Alex","Louis","Alex","Simon","Matthew", "Carl", "Simon"};
我想创建一个新的int数组,其大小相同,并且每个索引元素都应等效于其来自原始字符串数组的字符串元素。最终结果应如下所示:
int names[7] = {0, 1, 0, 2, 3, 4, 2};
如何实现以这种方式用数字填充整数数组的算法?
我已经从这种伪代码开始了,但是到目前为止绝对没有意义:
for (int i = 0; i < 7; i++) {
int counter = 0;
if names_str[i] has already been used
names[i] = assign the number
else
names[i] = counter;
counter++;
}
答案 0 :(得分:1)
您可以使用std::map
来跟踪已知的字符串计数器,例如:
#include <string>
#include <map>
std::string names_str[7] = {"Alex", "Louis", "Alex", "Simon", "Matthew", "Carl", "Simon"};
int names[7];
std::map<std::string, int> counter_map;
int counter = 0;
for (int i = 0; i < 7; ++i)
{
auto iter = counter_map.find(names_str[i]);
if (iter == counter_map.end())
iter = counter_map.insert(std::make_pair(names_str[i], counter++)).first;
names[i] = iter->second;
}
或者,由于insert()
将iterator
返回到现有的键元素(如果键已经存在),则可以避免通过find()
进行冗余搜索:
#include <string>
#include <map>
std::string names_str[7] = {"Alex", "Louis", "Alex", "Simon", "Matthew", "Carl", "Simon"};
int names[7];
std::map<std::string, int> counter_map;
int counter = 0;
for (int i = 0; i < 7; ++i)
{
auto ret = counter_map.insert(std::make_pair(names_str[i], counter));
if (ret.second) ++counter;
names[i] = ret.first->second;
}
无论哪种方式,由于您要将一个数组“转换”为另一个相同大小的数组,因此这是std::transform()
的一个好用例:
#include <string>
#include <map>
#include <algorithm>
std::string names_str[7] = {"Alex", "Louis", "Alex", "Simon", "Matthew", "Carl", "Simon"};
int names[7];
std::map<std::string, int> counter_map;
int counter = 0;
std::transform(std::begin(names_str), std::end(names_str), std::begin(names),
[&](const std::string &name) {
auto iter = counter_map.find(name);
if (iter == counter_map.end())
iter = counter_map.insert(std::make_pair(name, counter++)).first;
return iter->second;
}
);
#include <string>
#include <map>
#include <algorithm>
std::string names_str[7] = {"Alex", "Louis", "Alex", "Simon", "Matthew", "Carl", "Simon"};
int names[7];
std::map<std::string, int> counter_map;
int counter = 0;
std::transform(std::begin(names_str), std::end(names_str), std::begin(names),
[&](const std::string &name) {
auto ret = counter_map.insert(std::make_pair(name, counter));
if (ret.second) ++counter;
return ret.first->second;
}
);
答案 1 :(得分:0)
@Remy Lebeau,今天毫无疑问地学到了一些东西,但是,也许@weno没想到会有这么复杂的解决方案(其中的一个)。他想出了C风格的数组,所以我想知道,是否有更多C风格的解决方案可以解决当前的问题。
因此,如果有人感兴趣,这是我的解决方案(添加了一些监视功能)。
#include <iostream>
#include <string>
int seen(int max,
std::string const& name,
std::string const names_str[]
) {
for(int i = 0; i < max; i++)
if (name == names_str[i])
return i;
return -1;
}
int main() {
std::string names_str[7] = {"Alex", "Louis", "Alex", "Simon", "Matthew",
"Carl", "Simon"};
int names[7]{0};
int counter {0};
std::cout << "Monitor:\n";
for(int i = 0; i < 7; i++) {
int before {-1};
if((before = seen(i, names_str[i], names_str)) != -1) { // found!
std::cout << i << ", " << before << '\n'; // monitor
names[i] = names[before];
} else {
std::cout << i << '\n'; // monitor
names[i] = counter++;
}
}
std::cout << "Result: \n";
for(int i = 0; i < 7; i++)
std::cout << names[i] << '\n';
}
仅此而已。
答案 2 :(得分:0)
难以与map提出的解决方案一样优雅。
但是,这是一个基于std :: stable_sort的使用std :: vector的解决方案。
这个想法只是在排序后检测重复。
一旦检测到重复,一个简单的循环(类似于OP提出的伪代码)就可以获取最终索引。
此程序在下文提供。
可以将这种方法改编为类似C的数组。
复杂度为O(nlogn),所以我认为尽管复杂度增加了,但它至少与map提出的解决方案一样有效。
但是,效率不可能成为此类练习中最重要的标准!
#include <iostream>
#include <vector>
#include <string>
#include <algorithm>
int main () {
std::vector<std::string> names {"Alex","Louis","Alex","Simon","Matthew", "Carl", "Simon"};
std::vector<int> index (names.size());
for (int i = 0; i < names.size(); i++) index[i] = i;
// Sort and duplicate index when repetition
std::stable_sort (index.begin(), index.end(), [&names] (int i, int j) {return names[i] < names[j];});
std::vector<bool> seen (names.size(), false);
std::vector<int> index_corrected (names.size());
index_corrected[0] = index[0];
for (int i = 1; i < index.size(); i++) {
if (names[index[i]] == names[index[i-1]]) {
seen[index[i]] = true;
index_corrected[index[i]] = index_corrected[i-1];
} else {
index_corrected[index[i]] = index[i];
}
}
std::vector<int> index_new (names.size());
int k = 0;
for (int i = 0; i < names.size(); i++) {
if (seen[i]) index_new[i] = index_new[index_corrected[i]];
else index_new[i] = k++;
}
for (auto i: index_new) std::cout << i << " ";
std::cout << "\n";
}