简体   繁体   English

如何在字符串中获取 std::set 字符作为字符串?

[英]How can I get a std::set of characters in a string, as strings?

I have a std::string .我有一个std::string I want the set of unique characters in it, with each character represented as a std::string .我想要其中的一组唯一字符,每个字符都表示为std::string

I can get the set of characters easily:我可以轻松获得字符集:

std::string some_string = ...
std::set<char> char_set(some_string.begin(), some_string.end());

And I could convert them to strings like this:我可以将它们转换为这样的字符串:

std::set<std::string> string_set;
for (char c: char_set) {
    string_set.emplace(1, c);
}

But such an approach seems awkward.但这样的做法似乎很别扭。 Is there a better (preferrably standard-library one-liner) way to do this?有没有更好的(最好是标准库单行)方法来做到这一点?

A transform can be used as a one-liner: transform可以用作单行:

transform(begin(some_string), end(some_string),
          inserter(string_set, begin(string_set)),
          [] (char c) -> std::string { return {c}; });

I wouldn't recommend using this solution though as it's horribly unreadable. 我不建议使用这个解决方案,因为它非常难以理解。 Typically you want to write code that is intuitive and easy to understand. 通常,您希望编写直观且易于理解的代码。 What you've written in your answer already suffices and I wouldn't recommend looking for short cuts to reduce your code into a one liner while sacrificing its clarity. 您在答案中所写的内容已经足够了,我不建议您寻找捷径,以便在牺牲清晰度的同时将代码缩减为单线。

You can use: 您可以使用:

std::for_each(some_string.begin(), some_string.end(),
              [&string_set] (char c) -> void { string_set.insert(std::string({c}));});

You can also use: 您还可以使用:

   for (char c: some_string)
   {
      string_set.insert(std::string{c});
   }

Working program: 工作计划:

#include <iostream>
#include <string>
#include <set>
#include <algorithm>

int main()
{
   std::string some_string = "I want the set of unique characters in it";
   std::set<std::string> string_set;
   for (char c: some_string)
   {
      string_set.insert(std::string{c});
   }

   for (std::string const& s: string_set)
   {
      std::cout << s << std::endl;
   }
}

Output: 输出:

I
a
c
e
f
h
i
n
o
q
r
s
t
u
w

Is there a better (preferrably standard-library one-liner) way to do this? 有没有更好的(最好的标准库单行)方式来做到这一点?

No. Anything you would find in the C++ Standard Library is intended for more complex cases where they simplify the code you would have to write otherwise. 不会。您在C ++标准库中找到的任何内容都适用于更复杂的情况,它们会简化您必须编写的代码。 In your case, your code is simpler . 在您的情况下, 您的代码更简单 Trying to force yourself to use something from the Standard Library for this would make your code more convoluted. 试图强迫自己使用标准库中的某些内容会使您的代码更加复杂。

Three answers have already been posted that demonstrate this - they do exactly what you want but they are nearly unreadable at a glance and they add unnecessary overhead when the compiler is unable to optimize them. 已经发布了三个答案来证明这一点 - 它们完全符合您的要求,但它们几乎无法读取,并且当编译器无法优化它们时会增加不必要的开销。

Your for loop is the better solution. 你的for循环是更好的解决方案。 It is simple, it conveys intent to the reader, and it is easy for the compiler to optimize. 它很简单,它向读者传达了意图,编译器很容易进行优化。 There's no reason to waste time looking for a more complex solution to a simple problem. 没有理由浪费时间寻找一个简单问题的更复杂的解决方案。

All solutions are correct, but you should always pick the simplest correct solution. 所有解决方案都是正确的,但您应该始终选择最简单的正确解决方案。 Write less code, not more. 写更少的代码,而不是更多。

I doubt that what you want is a great idea, if you really insist, you could create a class that supports implicit conversion from char , implicit conversion to std::string , and can be compared with either another instance of itself or to a string: 我怀疑你想要的是一个好主意,如果你真的坚持,你可以创建一个支持从char隐式转换的类,隐式转换为std::string ,并且可以与其自身的另一个实例或字符串进行比较:

class cvt {
    char val;
public:
    cvt(char val) : val(val) {}

    bool operator<(cvt other) const { return val < other.val; }

    bool operator<(std::string const &s) const {
        return !s.empty() && val < s[0];
    }
    friend bool operator<(std::string const &s, cvt const &c) {
        return !s.empty() && s[0] < c.val;
    }
    operator std::string() const { return std::string(1, val); }
};

With this, we can create our set<cvt> , but use it as if it were a set<std::string> (since the elements in it can/will convert to std::string implicitly and compare with std::string ): 有了这个,我们可以创建我们的set<cvt> ,但是使用它就像它是一个set<std::string> (因为它中的元素可以/将隐式转换为std::string并与std::string进行比较):

int main() {
    std::string some_string = "ZABCDECD";

    // Create our (sort of) set<string> from characters in some_string:
    std::set<cvt> char_set(some_string.begin(), some_string.end());

    // An actual set<string> to use with it:    
    std::set<std::string> strings{ "A", "C", "E", "F", "Y" };

    // demonstrate compatibility:
    std::set_intersection(char_set.begin(), char_set.end(), strings.begin(), strings.end(),
        std::ostream_iterator<std::string>(std::cout, "\n"));
}

Live on Coliru . 住在Coliru

If we look at the generated code for this on Godbolt , we see that it really is nearly all syntactic sugar--the only code that's actually generated for the cvt class are the tiny bits to copy a byte in to create a cvt from a char , and to compare a cvt to a string . 如果我们在Godbolt上查看为此生成的代码 ,我们会发现它几乎都是语法糖 - 实际为cvt类生成的唯一代码是复制字节以从char创建cvt的微小位,并将cvtstring进行比较。 Everything else has been optimized out of existence. 其他一切都已经过优化。

If we're sure our strings won't be empty, we can simplify the comparisons to return val < s[0]; 如果我们确定我们的字符串不会为空,我们可以简化比较以return val < s[0]; and return s[0] < val; return s[0] < val; , in which case they get optimized away as well, so the only code that's generated from using cvt is a copying a byte from the source to construct a cvt object. 在这种情况下,它们也会被优化掉,所以使用cvt生成的唯一代码是从源复制一个字节来构造一个cvt对象。

Depending on what you have in mind, that might fit what you want. 根据您的想法,这可能符合您的要求。 It's a fair amount of extra typing, but it optimizes nicely--to the point that it's probably faster to compare a cvt to a string than to compare a string to a string . 这是一个相当多的额外输入,但它很好地优化 - 到将cvt与字符串进行比较可能比将stringstring进行比较要快得多。 By far the largest disadvantage is likely to stem from questioning your basic premise, and wondering why you wouldn't just write a loop and be done with it. 到目前为止,最大的缺点可能源于质疑你的基本前提,并想知道为什么你不会只写一个循环并完成它。

string setToString(const set<char> &s) {
    string str = "";
    std::accumulate(s.begin(), s.end(), str);
    return str;
}

Maybe this could be useful.也许这可能有用。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 如何使用 std::string 的成员函数删除字符串的第一个和最后一个字符,而不使用 remove_if、erase 等? - How can I delete first and last characters of strings using member functions of std::string, without using remove_if, erase, etc? 如何获得 std::map 的 std::set 键 - how can I get a std::set of keys to a std::map 如何获取 std::string 中的字符数? - How to get the number of characters in a std::string? 如何获得std :: set的相对索引? - How can I get relative index of std::set? 如何从枚举类型获取std :: string? - How can I get a std::string from an enum type? 我可以使用std :: set <std::string> 作为功​​能的默认参数? - Can I use std::set<std::string> as a default parameter for a function? 如何在没有std :: string中介的情况下创建一个支持通过C字符串查找的set <string>? - How can I make a set<string> that supports lookup via C string, without a std::string intermediary? 为什么std :: is_literal_type <std::String> ==错误,我该如何解决? - Why does std::is_literal_type<std::String> == false and how can I get around it? 我如何将这个 std::string 转换为 std::basic 字符串? - How would I get convert this std::string into a std::basic string? 我如何将std :: string复制到带有std :: string字段的结构中 - How can I std::copy a string to a struct with the std::string fields
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM