簡體   English   中英

如何在字符串中獲取 std::set 字符作為字符串?

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

我有一個std::string 我想要其中的一組唯一字符,每個字符都表示為std::string

我可以輕松獲得字符集:

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

我可以將它們轉換為這樣的字符串:

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

但這樣的做法似乎很別扭。 有沒有更好的(最好是標准庫單行)方法來做到這一點?

transform可以用作單行:

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

我不建議使用這個解決方案,因為它非常難以理解。 通常,您希望編寫直觀且易於理解的代碼。 您在答案中所寫的內容已經足夠了,我不建議您尋找捷徑,以便在犧牲清晰度的同時將代碼縮減為單線。

您可以使用:

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

您還可以使用:

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

工作計划:

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

輸出:

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

有沒有更好的(最好的標准庫單行)方式來做到這一點?

不會。您在C ++標准庫中找到的任何內容都適用於更復雜的情況,它們會簡化您必須編寫的代碼。 在您的情況下, 您的代碼更簡單 試圖強迫自己使用標准庫中的某些內容會使您的代碼更加復雜。

已經發布了三個答案來證明這一點 - 它們完全符合您的要求,但它們幾乎無法讀取,並且當編譯器無法優化它們時會增加不必要的開銷。

你的for循環是更好的解決方案。 它很簡單,它向讀者傳達了意圖,編譯器很容易進行優化。 沒有理由浪費時間尋找一個簡單問題的更復雜的解決方案。

所有解決方案都是正確的,但您應該始終選擇最簡單的正確解決方案。 寫更少的代碼,而不是更多。

我懷疑你想要的是一個好主意,如果你真的堅持,你可以創建一個支持從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); }
};

有了這個,我們可以創建我們的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"));
}

住在Coliru

如果我們在Godbolt上查看為此生成的代碼 ,我們會發現它幾乎都是語法糖 - 實際為cvt類生成的唯一代碼是復制字節以從char創建cvt的微小位,並將cvtstring進行比較。 其他一切都已經過優化。

如果我們確定我們的字符串不會為空,我們可以簡化比較以return val < s[0]; return s[0] < val; 在這種情況下,它們也會被優化掉,所以使用cvt生成的唯一代碼是從源復制一個字節來構造一個cvt對象。

根據您的想法,這可能符合您的要求。 這是一個相當多的額外輸入,但它很好地優化 - 到將cvt與字符串進行比較可能比將stringstring進行比較要快得多。 到目前為止,最大的缺點可能源於質疑你的基本前提,並想知道為什么你不會只寫一個循環並完成它。

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

也許這可能有用。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM