将字符串数组转换为整数数组

时间:2018-11-18 22:14:29

标签: c++ arrays transform

我有以下字符串数组:

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++;
}

3 个答案:

答案 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;
}

Live Demo

或者,由于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;
}

Live Demo

无论哪种方式,由于您要将一个数组“转换”为另一个相同大小的数组,因此这是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;
    }
);

Live demo

#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;
    }
);

Live Demo

答案 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";  
}