Swapping two random numbers

Hi everyone, I'm new to C++ programming language. This post is a continuation of my previous post (http://www.cplusplus.com/forum/beginner/257709/).
Looking at the previous post was too long ago, I decide to write a new post. I would like to ask about swapping. I'm trying to use c++ built in function swap() but doesn't work. Can someone here teach me the right way to do it. Any suggestion/help much appreciated. Thank you in advance :)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
#include <iostream>
#include <iomanip>
#include <fstream>
#include <sstream>
#include <string>
#include <vector>
#include <random>
#include <iterator>
#include <algorithm>

using namespace std;

void print_route(const std::vector<int>& original)
{
	for (int v : original) cout << v << setw(5);
	cout << '\n';
}

int main()
{
	mt19937 rng(random_device{}());

	ifstream original("routes_p102.txt");
	vector<vector<int>> ori_data;

	for (string line; getline(original, line); )
	{
		ori_data.push_back(vector<int>());
		istringstream iss(line);
		for (int n; iss >> n; )
			ori_data.back().push_back(n);
	}

	cout << "Original vector:\n";
	for (auto& r : ori_data)
	{
		print_route(r);
	}
	cout << endl;

	// for each row in the route
	// range based loop: http://www.stroustrup.com/C++11FAQ.html#for
	// auto: http://www.stroustrup.com/C++11FAQ.html#auto

	for (const auto& row : ori_data)
	{
		// select two random numbers other than { 0, 1, 2 } from this row
		// 1. make a copy of this row
		// https://cal-linux.com/tutorials/vectors.html
		std::vector<int> copy(begin(row), end(row));

		// 2. shuffle the copy randomly
		// https://en.cppreference.com/w/cpp/algorithm/random_shuffle
		std::shuffle(begin(copy), end(copy), rng);

		// 3. pick the first two values in the shuffled copy that are not in { 0, 1, 2 }
		//cout << "For row [ " << row << " ] " << "select ";
		int nselected = 0;
		for (int v : copy)
		{
			if (v != 0 && v != 1 && v != 2)
			{
				if (nselected == 1) cout << " and ";
				cout << v;
				nselected++;
				if (nselected == 2) break;

				// Swap two random values
				//swap((nselected == 1),(nselected == 2));
			}
		}
		if (nselected == 0) cout << "nothing (did not find any suitable number)\n";
		else if (nselected == 1) cout << " (found only one suitable number)\n";
		else cout << '\n'; // found two
	}
	cout << '\n';

	// print new vector after swapping
	cout << "New vector:\n";
	for (auto& r : ori_data)
	{
		print_route(r);
	}
	cout << endl;
}
its literally just swap(a,b);
to swap 2 things in a vector,
swap[vec[indexa], vec[indexb]);

you cannot swap literals..
swap(3,4); //this is nonsense, because 3 and 4 are not stored anywhere, you can't make 3 be 4, its 3!

boolean expressions as you have them are like literals:
nselected==1 is going to be a literal 0 or 1 ... you cannot swap expressions. (the correct word here is lvalue, if you have seen this).

some languages may allow this kind of thing -- they may turn 3 into an unnamed variable and be able to flip the values -- but c++ does not do this.
Last edited on
Hi! In the future, if something doesn't work, telling us about the errors (or behavior) your get that you don't want is really helpful.

I'm guessing you're talking about this commented line:swap((nselected == 1),(nselected == 2));

Variables do not have "memory" of their previous values, and even if they did, you wouldn't be getting them using ==.

You'll need some way of getting references to the two values you want to swap. Your range-based for loop (lines 59 to 71) actually makes this a bit awkward, but you can still use such a loop by having v be a reference to an int and declaring a pointer variable outside of the loop which you set to the address of the first element inside the loop.

Alternatively, you can use a traditional for loop, where you'll have easier access to the indexes (or iterators).

Take care,
-Albatross
Hi Jonnin and Albatross, thank you for your advice.

I had change the code line 69 as follows, but two errors occured.

 
swap(v[nselected == 1], v[nselected == 2]);


Errors:
subscript requires array or pointer type
'std::swap': function does not take 1 arguments

Can you teach me by showing me the right way. Thank you for your help.

you can cast an expression to an index:

v[(int)(nselected==1)] but this is almost certainly not what you want.

lets try it again.
try

swap(v[1], v[2]); //remember, 0 is the first element, so this swaps the second and third elements

if you do not understand what exactly this is doing, you need to stop what you are doing and review conditional statements before trying to tackle a bigger program.

v[(int)(nselected==1)] what do you think this means?!
Last edited on
v[(int)(nselected==1)] what do you think this means?!

This refer to first random number chosen from v. Am I right ?

I had try change it to swap(v[1], v[2]), but same errors still occurred.

Its quite confusing.
Last edited on
Nope, sorry. Friendly reminder: you've been using nselected to store how many elements you've selected, == compares things, and v is an int, not an std::vector.

Let me try and make what I wrote earlier a little bit clearer: you should change your loop. For you to swap two things in a vector, you need references (or iterators) to both them. Your loop, as it is now, makes getting those references very awkward.

The most understandable way for you to do it would probably be to just use a traditional for loop, and store the value of i when you find the right value of copy[i].

Otherwise, were you a bit further along, I'd recommend a couple of calls to std::find_if and one call to std::iter_swap.

-Albatross
Hi Albatross, thanks for suggestions.

I will try change it first. Hopefully everything going smooth.

Thank you :)
sorry about that I did not look at the code close enough and thought V was your vector.

look... a 10 second, super simple example:
1
2
3
4
5
6
7
vector<int> whatever(10);
for(int i = 0; i < 10; i++)
  whatever[i] = i;

swap(whatever[0], whatever[9]); //the array index can be variables, whatever integers. 
for(int i = 0; i < 10; i++)
cout << whatever[i] << endl;


this is what he is saying to do, with a traditional loop setup..



v[(int)(nselected==1)] what do you think this means?!

This refer to first random number chosen from v. Am I right ?

no. Pretend for a second that V is a vector because I was not paying attention ...
from the inside out, this asks "is nselected equal to 1" and responds with c++ for "yes or no" (true or false) which is 0 for false, 1 for true.
so this would go into your vector to the 0 or 1 location and get the data there. It is NOT at ALL what you wanted.

Last edited on
Thank you Jonnin for your suggestion and explanations.

I will study and try to code it.

Thank you :)
Topic archived. No new replies allowed.