11

I have to construct an ordered container (which must be iterable) with the following rule:

If the condition is true, the container is {1,0}, else it's {0,1}

I have the following code, but I don't find it "elegant":

   vector<int> orderedSides;
   if (condition) 
   {
       orderedSides.push_back(1);
       orderedSides.push_back(0);
   }
   else            
   {
       orderedSides.push_back(0);
       orderedSides.push_back(1);
   }

Is there a better way to do this (from concision and performance point of view)?

Rakete1111
  • 47,013
  • 16
  • 123
  • 162
youyou
  • 173
  • 1
  • 11
  • 1
    You can make a call to reserve before you implement it. Ultimately, the std::initializer_list constructors aren't better from a performance standpoint, as they have to copy data into the container. – Alex Huszagh Jun 30 '17 at 08:02
  • Before C++11 that's basically the only way to do it. – Some programmer dude Jun 30 '17 at 08:04
  • @Someprogrammerdude For C++ noobs: what would be the way to do this in C++11? – Right leg Jun 30 '17 at 13:23
  • 1
    @Rightleg `vector orderedSided = { condition, !condition }`. *Iff* `condition` is a `bool` expression. If `condition` is otherwise convertible to `int` (or of course is an `int`) but the result might not be `1` or `0`, then `{ !!condition, !condition }` – Some programmer dude Jun 30 '17 at 14:59
  • @Someprogrammerdude Wow that's cool. Thanks! – Right leg Jun 30 '17 at 15:41
  • There's nothing wrong with this code. All the answers make it more complicated for nothing. – isanae Jun 30 '17 at 17:36

6 Answers6

16

You might implement something like this:

vector<int> orderedSides(2, 0);
(condition ? orderedSides.front() : orderedSides.back()) = 1;

which is a little bit shorter than explicit if clauses.

As @Deduplicator mentioned below, we might rewrite the second line in a more concise way:

orderedSides[!condition] = 1;
YSC
  • 38,212
  • 9
  • 96
  • 149
Edgar Rokjān
  • 17,245
  • 4
  • 40
  • 67
  • 1
    `orderedSides[!condition] = 1;` as the second line is even shorter and relies less on the optimizer. – Deduplicator Jun 30 '17 at 10:27
  • @Deduplicator Exactly, perfect note! – Edgar Rokjān Jun 30 '17 at 10:41
  • 3
    I find this code much harder to read and the intent is very unclear. I don't really like the bool cast either, but that ones just my opinion. The OP should steer clear of this. No down-voting, as the OP did say brevity was the most important thing, it might even be for code golf for example? – Nathan Cooper Jun 30 '17 at 11:11
  • The OP also mentioned performance, and this looks bad performance-wise. You have a input-dependent address, which always aliases one of the two prior stores. That's the sort of thing that an OOO CPU dislikes. @Some programmer dude's answer (in the comments, boo!) looks better as it has two definitely unrelated stores. – MSalters Jun 30 '17 at 15:53
  • if the condition is true, the array should be in descending order. maybe `[!condition]` would read nicer with a different name, say `[!descending]` – Mic Jun 30 '17 at 16:13
5
vector<int> orderedSides;
orderedSides.push_back(condition ? 1 : 0);
orderedSides.push_back(condition ? 0 : 1);

I don't think it's more performant but I find it more elegant.

Antoine Thiry
  • 2,362
  • 4
  • 28
  • 42
1

You could compromise between efficiency and avoiding repetition, initialise the first with the condition and the second from the first.

vector<int> orderedSides(1, bool(condition)) ;
orderedSides.push_back(!orderedSides.back());
Mic
  • 331
  • 1
  • 4
0
orderedSides.push_back(0);
orderedSides.push_back(1);
if (condition)
  std::iter_swap(orderedSides.begin(), orderedSides.begin()+1);

I know this take bits cost. As one of candidates.

mattn
  • 7,571
  • 30
  • 54
0

You can populate a std::vector from an array, even in C++98.

Here's an example:

#include <iostream>
#include <vector>

int main() {
    bool condition = false;
    std::cout << "condition is: " << std::boolalpha << condition << '\n';

    int arr[][2] = {{0,1}, {1,0}};
    int index = condition;
    std::vector<int> v(arr[index], arr[index]+2);

    for (int i = 0; i < v.size(); i++)
        std::cout << v[i] << ' ';
    std::cout << '\n';
}

The output is:

$ g++ tt.cc && ./a.out
condition is: false
0 1 

For reference:

moooeeeep
  • 31,622
  • 22
  • 98
  • 187
  • How is that constructor implemented in a typical C++03 standard library implementation? Is it just doing a `for` loop over the array internally? – Cody Gray - on strike Jun 30 '17 at 16:11
  • @CodyGray I'd hope that the implementation would resize/reserve enough memory first. But then, I don't think it makes much of a difference whether you write down a loop or memcpy or std::copy to implement this, I guess. – moooeeeep Jul 02 '17 at 09:19
0

If building the elements (the ints in your question, whatever it is in real life) is free and side-effect-less:

static const int data[] = { 0, 1, 0 };
std::vector<int> orderedSides (data+condition, data+condition+2);

Full program example:

#include <iostream>
#include <vector>

std::vector<int> make(bool cond)
{
    static const int data[] = { 0, 1, 0 };
    return std::vector<int> (data+cond, data+cond+2);
}

std::ostream& operator<<(std::ostream& os, const std::vector<int>& v)
{
    return os << "{ " << v[0] << ", " << v[1] << " }";
}    

int main()
{
    std::cout << "true:  " << make(true) << "\n"
              << "false: " << make(false) << "\n";
}

Prints:

true:  { 1, 0 }
false: { 0, 1 }

Demo

YSC
  • 38,212
  • 9
  • 96
  • 149