sorted([(k.weight, k.name) for k in somelist], reverse=True) sorted([(k.weight, k.name) for k in somelist], reverse=True) std::vector<std::pair<float, std::string>> in_order;
std::transform(data.begin(), data.end(), std::back_inserter(in_order),
[](auto& item) {return std::make_pair(item.weight, item.name);});
std::sort(in_order.begin(), in_order.end(), std::greater<>());
While I won't claim it to be as elegant as Python, it doesn't seem too ugly. Does anybody have an idea about how `auto` could be utilized to avoid the long vector<pair...> type declaration?For the adventurous: https://repl.it/repls/RepentantGentleKudu
Pulling things out of tuples isn't great, though.
Right now, I think that's approximately,
vector<tuple<int, string>> output;
transform(
somelist.begin(), somelist.end(),
back_inserter(output),
[](const auto &f) { return make_tuple(f.weight, f.name); }
);
sort(output.rbegin(), output.rend());
Ranges, I believe, would reduce this a lot, possibly even to a single line. If I am reading the docs on it correctly, something like, vector<auto>(somelist | view::transform([](const auto &f) { return make_tuple(f.weight, f.name); })) | action::sort;
I think.Two notes, however:
1. I feel like most of the desire for a static language is to know what type something is. Is C++ exactly as brief as Python? No, as I think you've demonstrated. But I think you're a lot more likely to know the type of something. Rarely do I think I find that Python has annotations, and annotations can be wrong.
2. C++ is, in general, I feel, much more explicit about where copies occur. I elided one of the copies in your example, opting instead for an in-place sort (but this is trivial to fix in the Python).
Sure, but you don't have to choose between them, there are plenty of languages where you can have both Pythonic terseness and full type safety. E.g. Scala:
(for {k <- somelist} yield (k.weight, k.name)).sorted.reverse
Many other strongly typed (ML-like) functional languages are similar.Really? O.o How could this possibly work?
somelist | transformed([](auto &&k) { return make_pair(k.weight, k.name); }) | sorted | reversed; std::vector<P> people = { P{"jane", 47}, P{"mary", 71}, P{"john", 65} };
ranges::sort(people, [](auto& x, auto& y){ return x.weight > y.weight; });
Compile this gist with `c++ -std=c++1z -I range-v3/include`:https://gist.github.com/cieplak/dcd587c67d989768900e4110e776...
someList.OrderByDescending(x => x.weight).ThenByDescending(x => x.Name);
It's quite similar to expressing the concept in English, certainly more than using list comprehension in Python.And how would you order it in Python by ascending on the first field and descending on the second using list comprehension?
In answer to your question though,
sorted(((k.weight, k.name) for k in some_list), key=lambda x: (-x[0], x[1]), reverse=True)
appears to work. This does use a non-obvious trick, but being more explicit is a smidge difficult, since the key function is called only n times, as opposed to O(nlogn) in the C# example.Alternatively, you can use
sorted(sorted(((k.weight, k.name) for k in some_list), key=lambda x: x[1], reverse=True), key=x[0])
Which is more like the original example, and if you're doing it in place, you get outs = [k.weight, k.name) for k in some_list]
outs.sort(key=lambda x: x[1], reverse=True)
outs.sort(key=lambda x: x[0])
Python's builtin sort is timsort, so despite sorting the list twice, this will still run in approximately NlogN comparisons, not 2NlogN.You could also manually define a custom comparator, ie
lambda s, o: (s[0] > o[0] * 10 + s[1] < o[1])
and pass it to `functools.cmp_to_key`.sorted( (k.weight, k.name).for_(k).in(somelist), reverse=true));
You would never be able to get that past code review, however.
The other thing to note is that
sorted([(k.weight, k.name) for k in somelist], reverse=True)
is essentially already typechecked: def biggest_ks(ks: K):
return sorted([(k.weight, k.name) for k in ks], reverse=True)
The above code now has all the same type guarantees as your c++, actually maybe more since the macros you use are going to be...uhhh, mysterious.My point was just that you can implement almost whatever you want (even without macros, they'll just expand the design space).