简体   繁体   English

自定义对字符串数组的排序

[英]Custom Sort on an array of Strings

Given an array of strings containing the seven colors of the rainbow but placed in random order, I am somehow supposed to sort this array to output Red, Orange, Green,....,Violet in that order. 给定一个包含彩虹的七种颜色但以随机顺序排列的字符串数组,我应该以某种方式对该数组进行排序,以按该顺序输出Red,Orange,Green .... Violet。 The order of rainbow colors. 彩虹色的顺序。 How can I sort this array? 如何排序此数组?

You should write a custom comparator. 您应该编写一个自定义比较器。 Here's how I would go about it. 这就是我要做的。

//somewhere in initalization code;
std::map<string, int> mapOrder;
mapOrder["red"] = 1;
mapOrder["orange"] = 2;
...
mapOrder["violet"] = 7;


bool isRainbowLess(const std::string& a, const std::string& b)
{
    return mapOrder[a] < mapOrder[b];
}


int main()
{
    std::vector<std::string> myVector;
    ....
    std::sort(myVector.begin(), myVector.end(), &isRainbowLess);
}

OK, please do not down vote it right away. 好的,请不要马上对其投下反对票。 I know this is a bad example. 我知道这是一个不好的例子。 I wrote it be cause OP specifically asked for a no-STL solution, and to present how (bad) would/could it look like. 我写这是因为OP专门要求提供无STL解决方案,并说明了它的(坏)情况。

Well, there you go. 好吧,你去。 The code is not completed. 代码未完成。 But you should get the general idea. 但是您应该了解一般的想法。 One thing I did skip is the sorting of integers itself. 我跳过的一件事是整数本身的排序。 Since it should be trivial. 既然应该是琐碎的。 As you can see, the mapping, is a little bit of PIA and looks quite bad. 如您所见,映射只是一点点PIA,看起来很糟糕。 But since you forbid to use STL there is no std::map . 但是由于您禁止使用STL,所以没有std::map Moreover, I implied static size of N for all the tables. 此外,我暗示所有表的静态大小为N It could be allocated dynamically, no problem, and no std::vector . 它可以动态分配,没有问题,也没有std::vector

I used else if s for map* functions to mimick std::map functionality. 我将else if s用于map*函数来模仿std::map功能。 Probably switch ... case could be used, but it should work pretty much the same on a decent compiler. 也许可以使用switch ... case ,但是在一个不错的编译器上它应该几乎一样工作。

The code I wrote below is pretty much the same in terms of functionality provided as Armen's does. 就提供的功能而言,我下面编写的代码与Armen的代码几乎相同。 I would recommend his solution. 我会推荐他的解决方案。 I skipped same parts. 我跳过了相同的部分。 So you can see it's uglier and more typing. 因此,您可以看到它更丑陋且输入更多。 It looks almost like pure C. Maybe with one modification if you really yearn for speed at very large cases. 它看起来几乎像纯C。如果您真的想在非常大的情况下提高速度,也许可以进行一次修改。 That would be using a temporary data structure that would hold mapped values, to sort it, and then map it back. 那将使用一个临时数据结构,该结构将保留映射的值,对其进行排序,然后再将其映射回去。 Precisely I would advise to avoid calling map::operator[](const &T) (or any accessor) on std::string under high performance constraints to avoid hash computations. 确切地说,我建议避免在高性能约束下在std::string上调用map::operator[](const &T) (或任何访问器),以避免哈希计算。 But that's only it. 但是,仅此而已。

There is also some more to discuss. 还有更多的讨论。 Like what if you wanted two colors to have the same value, or use non-integer weights. 例如,如果您希望两种颜色具有相同的值,或者使用非整数权重。 STL based solution is way more adaptable. 基于STL的解决方案更具适应性。

Cheers. 干杯。

The code: 代码:

/* This will map color literals (color names) to integers, which will associate them with 
   a numerical value, than can be used for comparison */
enum Colors { Red, Orange, Green, /*...*/ Violet };

/* this should read colors as std::string instances from the input array and assing
   the the appropriate color codes into output array at corresponding indexes     */
void mapString2Color( const std::string* input, int* output, size_t N ){
  for(size_t i = 0; i < N; i++){
    if ( input[i] == std::string("red") ) output[i] = Colors::Red;
    else if ( input[i] == std::string("orange") ) { output[i] = Colors::Orange; }
    else if ( input[i] == std::string("green") )  { output[i] = Colors::Green;  }
    /*...*/
    else if ( input[i] == std::string("violet") ) { output[i] = Colors::Violet; }
    else {/*unspecified color code */}
  }
}
/* this is supposed to do the opposite to mapString (i.e. put appropriate 
   string at output[i] based on input[i])  */
void mapColor2String( const int* input, std::string* output, size_t N ){
  for(size_t i = 0; i < N; i++){
    if ( input[i] == Colors::Red ) output[i] = std::string("red");
    else if ( input[i] == Colors::Orange ) { output[i] = std::string("orange"); }
    else if ( input[i] == Colors::Green  ) { output[i] = std::string("green");  }
    /*...*/
    else if ( input[i] == Colors::Violet ) { output[i] = std::string("violet"); }
    else {/*unspecified color index*/}
  }
}

void sort(int* array, size_t N){
 /* any in-place sort of your liking for table of (unsigned) integers */
}

main(){
  std::string[N] input_array;
  std::string[N] output_array;
  int[N] temp_array;

  //map (translate) colors to their numerical values
  mapString2Color(input_array, temp_array, N);
  //sort it
  sort(temp_array, N);
  //map (translate) the values back to color names
  mapColor2String(temp_array, output_array, N);
}

First thing I would do is to create a mapping. 我要做的第一件事是创建映射。 You could do this either via a map or by linearly iterating over a presorted array of strings and taking the index of the matching entry. 您可以通过映射或线性迭代预排序的字符串数组并获取匹配条目的索引来执行此操作。 A very simple way (for demonstration purposes really) might be simply to encode the logic into an encapsulated function as follows: 一种非常简单的方法(实际上只是出于演示目的)可能是将逻辑编码为封装的函数,如下所示:

int intForCol( const string& col ) 
{
    if ( col == "red" ) return 0; 
    else if ( col == "orange" ) return 1;
    else if ( col == "yellow" ) return 2;
    else if ( col == "green" ) return 3;
    else if ( col == "blue" ) return 4;
    else if ( col == "indigo" ) return 5;
    else if ( col == "violet" ) return 6;
    throw "Invalid colour"; 
}

This will provide an ordering integer based on the input string. 这将基于输入字符串提供一个排序整数。 The next step is to create a comparator: 下一步是创建一个比较器:

int colComp( const string& lhs, const string& rhs )
{
    return intForCol( lhs ) - intForCol( rhs );
}

This will allow us to compare strings together returning negative if lhs < rhs and positive if lhs > rhs 这将使我们能够比较字符串连接在一起返回负,如果lhs < rhs和正面的,如果lhs > rhs

This can now be used within the STL - either as the comparitor within an associative container or directly in a sort algorithm - with relative ease. 现在,可以相对轻松地在STL中使用它(将其用作关联容器中的比较器,或者直接在排序算法中使用)。 Alternatively, if using STL is out of the question or the point of this is to understand how sorting works, you could implement your own sort like the simple and (very) inefficient algorithm below: 另外,如果无法使用STL或这样做的目的是了解排序的工作原理,则可以实现自己的排序,例如下面的简单(非常低效)算法:

    const int col_size = 7;
    string input[col_size];
    input[0] = "indigo";
    input[1] = "green";
    input[2] = "red";
    input[3] = "blue";
    input[4] = "yellow";
    input[5] = "violet"; 
    input[6] = "orange";

    // simple bubble sort
    int passes = col_size;
    int last = col_size; 
    while ( passes-- )
    {
        for ( int i = 0; i < last - 1; ++i ) 
            if ( colComp( input[i], input[i+1] ) > 0 )
            {
                string temp = input[i]; input[i] = input[i+1]; input[i+1] = temp;
            }
        last--;
    }

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

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM