Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Sorting a set<string> on the basis of length

My question is related to this.

I wanted to perform a sort() operation over the set with the help of a lambda expression as a predicate.

My code is

#include <set>
#include <string>
#include <iostream>
#include <algorithm>
int main() {
  using namespace std;
  string s = "abc";
  set<string> results;
  do {
    for (int n = 1; n <= s.size(); ++n) {
      results.insert(s.substr(0, n));
    }
  } while (next_permutation(s.begin(), s.end()));

  sort (results.begin(),results.end());[](string a, string b)->bool{

              size_t alength = a.length();
              size_t blength = b.length();
              return (alength < blength);
  });
  for (set<string>::const_iterator x = results.begin(); x != results.end(); ++x) {
    cout << *x << '\n';
  }
  return 0;
}

But the numbers and types of errors were so complex that I couldn't understand how to fix them. Can someone tell me whats wrong with this code.

like image 336
Tester Avatar asked Oct 02 '10 08:10

Tester


People also ask

How to sort a list based on the length of string?

1. Initialize the list of strings. 2. Sort the list by passing key to the sort(key = len) method of the list. We have to pass len as key for the sort() method as we are sorting the list based on the length of the string. sort() method will sort the list in place. So, we don't need to store it in new variable. 3. Print the list. Example. Live Demo

How to arrange the strings in ascending order according to length?

We have to arrange the strings in ascending order according to their lengths. We can do this using our algorithms or Python built-in method sort () or function sorted () along with a key. Let's take an example to see the output. Input: strings = ["hafeez", "aslan", "honey", "appi"] Output: ["appi", "aslan", "honey", "hafeez"]

Can a set contain strings with different contents but same length?

Now the set can only contain one string of any given length, rather than any given value. Your output is in error; to get that would require multiset. @Potatoswatter: The question author's program will ignore strings with different contents but same length. But the author described nowhere the intent of the program. Only that it was bugged.

How to sort a list in Python using C++ STL sort?

A better solution is to use sort function provided by programming languages like C++, Java. These functions also allow us to write our own custom comparator. Below is C++ implementation that uses C++ STL Sort function . Take string as list. Use the sorted function in python by providing key as len.


4 Answers

Edit: Note that Steve Townsend's solution is actually the one you're searching for, as he inlines as a C++0x Lambda what I write as C++03 code below.

Another solution would be to customize the std::set ordering function:

The std::set is already ordered...

The std::set has its own ordering, and you are not supposed to change it once it is constructed. So, the following code:

int main(int argc, char* argv[])
{
    std::set<std::string> aSet ;

    aSet.insert("aaaaa") ;
    aSet.insert("bbbbb") ;
    aSet.insert("ccccccc") ;
    aSet.insert("ddddddd") ;
    aSet.insert("e") ;
    aSet.insert("f") ;

    outputSet(aSet) ;

    return 0 ;
}

will output the following result:

 - aaaaa
 - bbbbb
 - ccccccc
 - ddddddd
 - e
 - f

... But you can customize its ordering function

Now, if you want, you can customize your set by using your own comparison function:

struct MyStringLengthCompare
{
    bool operator () (const std::string & p_lhs, const std::string & p_rhs)
    {
        const size_t lhsLength = p_lhs.length() ;
        const size_t rhsLength = p_rhs.length() ;

        if(lhsLength == rhsLength)
        {
            return (p_lhs < p_rhs) ; // when two strings have the same
                                     // length, defaults to the normal
                                     // string comparison
        }

        return (lhsLength < rhsLength) ; // compares with the length
    }
} ;

In this comparison functor, I did handle the case "same length but different content means different strings", because I believe (perhaps wrongly) that the behaviour in the original program is an error. To have the behaviour coded in the original program, please remove the if block from the code.

And now, you construct the set:

int main(int argc, char* argv[])
{
    std::set<std::string, MyStringLengthCompare> aSet ;

    aSet.insert("aaaaa") ;
    aSet.insert("bbbbb") ;
    aSet.insert("ccccccc") ;
    aSet.insert("ddddddd") ;
    aSet.insert("e") ;
    aSet.insert("f") ;

    outputSet(aSet) ;

    return 0 ;
}

The set will now use the functor MyStringLengthCompare to order its items, and thus, this code will output:

 - e
 - f
 - aaaaa
 - bbbbb
 - ccccccc
 - ddddddd

But beware of the ordering mistake!

When you create your own ordering function, it must follow the following rule:

return true if (lhs < rhs) is true, return false otherwise

If for some reason your ordering function does not respect it, you'll have a broken set on your hands.

like image 141
paercebal Avatar answered Oct 14 '22 16:10

paercebal


std::sort rearranges the elements of the sequence you give it. The arrangement of the sequence in the set is fixed, so the only iterator you can have is a const iterator.

You'll need to copy results into a vector or deque (or such) first.

vector sortable_results( results.begin(), results.end() );
like image 22
Potatoswatter Avatar answered Oct 14 '22 14:10

Potatoswatter


You can customize the ordering of the elements in the set by providing a custom predicate to determine ordering of added elements relative to extant members. set is defined as

template <
    class Key, 
    class Traits=less<Key>, 
    class Allocator=allocator<Key> 
>
class set

where Traits is

The type that provides a function object that can compare two element values as sort keys to determine their relative order in the set. This argument is optional, and the binary predicate less is the default value.

There is background on how to use lambda expression as a template parameter here.

In your case this translates to:

auto comp = [](const string& a, const string& b) -> bool 
    { return a.length() < b.length(); };
auto results = std::set <string, decltype(comp)> (comp);

Note that this will result in set elements with the same string length being treated as duplicates which is not what you want, as far as I can understand the desired outcome.

like image 24
Steve Townsend Avatar answered Oct 14 '22 15:10

Steve Townsend


sort requires random access iterators which set doesn't provide (It is a bidirectional iterator). If you change the code to use vector it compiles fine.

like image 32
Naveen Avatar answered Oct 14 '22 15:10

Naveen