how can we fill a set in C++ from user input in one liner
I know we can store input in a variable and then use
set.insert(some_variable)
but cant we take input from user directly?
like set.insert(cin>>set[i])?
I am just a beginner.
You can copy the values into a std::set with std::copy_n. (Please see here)
The source will be the std::istream_iterator (described here) and the destination will be the std::inserter wrapper (described here).
Please see:
#include <iostream>
#include <set>
#include <iterator>
#include <algorithm>
int main() {
// Our set
std::set<int> s{};
// How many values do we want to read
const size_t numberOfUserInputs{ 3 };
// Copy values from std::cin to set
std::copy_n(std::istream_iterator<int>(std::cin), numberOfUserInputs, std::inserter(s, s.begin()));
// Debug output
for (int i : s) std::cout << i << '\n';
return 0;
}
no, you can't do this.
things that go with vector like
std::vector<int> he;
auto endf = he.end();
*he.insert(endf, 1) = 5;
will not go with set. insert returns const_iterator.
Related
I have an array:
names[4]={john,david,jack,harry};
and i want to do it randomly shuffle, like:
names[4]={jack,david,john,harry};
I tried to use this but it just shuffled the letters of the first word in the array:
random_shuffle(names->begin(), names->end());
Here is the full code, it reads names from a .txt file and puts in an array:
#include <iostream>
#include <fstream>
#include <string>
#include <algorithm>
using namespace std;
int main() {
ifstream readName("names.txt");
string names[197];
int i = 0;
for (string line; getline(readName, line); ){
readName >> names[i];
i++;
}
readName.close();
random_shuffle(names->begin(), names->end());
for (int i = 0; i < 197; i++) {
cout << names[i] << endl;
}
return 0;
}
I tried few other things from different people but I couldn't manage to work it.. Anything helps, thank you!
Here's your code with what I felt were the smallest amount of changes. One could argue that I didn't need to change your first for loop as much, but I figure that if you have the prescience to know how many names you're reading, you might as well use the knowledge.
#include <algorithm>
#include <fstream>
#include <iostream>
#include <iterator> // std::begin(), std::end(); required for C-arrays
#include <random> // std::mt19937; needed to feed std::shuffle()
#include <string>
// using namespace std; // BAD PRACTICE
int main() {
constexpr int size = 4; // Give your magic number a name; only need to change
// a single location
std::ifstream readName("names.txt");
if (!readName) { // Always check that you successfully opened the file.
std::cerr << "Error opening file.\n";
return 1;
}
std::string names[size];
// int i = 0;
for (int i = 0; i < size; ++i) { // Retool the loop entirely
std::getline(readName, names[i]);
}
readName.close();
// This is a fragile solution. It's only working because the array is in
// scope
std::shuffle(std::begin(names), std::end(names),
std::mt19937{std::random_device{}()});
for (int i = 0; i < size; i++) {
std::cout << names[i]
<< '\n'; // Don't use std::endl unless you actually need it
}
return 0;
}
This is not ideal code, though. Any change to the size of the input file requires changing the code and re-compiling. The biggest single change was to get rid of std::random_shuffle and use std::shuffle() instead. std::random_shuffle was deprecated with C++14 and removed in C++17. It's bad to use it. std::shuffle() does add the requirement of providing a PRNG, but it's not so bad. It leads to better code if you have a PRNG that needs to randomize many different things in a bigger program. This is because it's good to have a single PRNG and let it live for the length of your program as opposed to constantly building new ones.
And the C-array just makes things a bit clunkier. Enter std::vector.
#include <algorithm>
#include <fstream>
#include <iostream>
#include <iterator>
#include <random> // std::mt19937; needed to feed std::shuffle()
#include <string>
#include <vector>
int main() {
std::ifstream readName("names.txt");
if (!readName) { // Always check that you successfully opened the file.
std::cerr << "Error opening file.\n";
return 1;
}
std::vector<std::string> names;
std::string name;
while (std::getline(readName, name)) { // Retool the loop entirely
names.push_back(name);
}
readName.close();
std::shuffle(std::begin(names), std::end(names),
std::mt19937{std::random_device{}()});
for (const auto& i : names) {
std::cout << i << '\n';
}
return 0;
}
The vector can grow as needed, so you see how much simpler the loop that reads the names becomes. It's also more flexible since you don't have to know ahead of time how many entries to expect. It will "just work." With the call to std::shuffle() I kept the std::begin(names) syntax because many consider this a best practice, but you could have also used names.begin() if you wanted since the vector class provides its own iterators.
Lets have a look at you main question:
I tried to use this but it just shuffled the letters of the first word in the array:
random_shuffle(names->begin(), names->end());
The reason that it only shuffles the first word is because of the types and usage.
So names is an array of strings.
string names[197];
The problem stems from the C world. Were arrays decay into pointers exceedingly easily (just by being used in an expression). So here names-> has decayed into a pointer to the first element of the array. This allows you to use the -> operator which normally only works on pointers. So you are calling the functions begin() and end() on the pointer to the first element in the array. Thus only the first name is being shuffled.
The fix this problem use std::begin() method.
// here std::begin / std::end find the beginning and end
// of the array. So you are shuffling the array.
random_shuffle(std::begin(names), std::end(names));
But I would note that random_shuffle() is outdated. As mentioned by #sweenish you should use std::shuffle() See his answer for details.
A couple of things we can improve:
You use C array to store the names. Sure it works, but it is susceptible to a couple of issues because it can not be re-sized (and unless you think the file is never going to be changed that may be an issue). Potentially a hidden issue to a far distant maintainer.
std::vector<std::string> names; // resizeable container.
I would note that the current implementation ignores the first line. Then reads the first word from each subsequent line. There is also a slight issue that the last line may be empty and you read an empty name into the last element of the array (but you don't track how many names you read so unless you use all elements in the array you may never notice that).
I would change that. As it is not obvious. I would delibrately and seprately ignore the first line. Then I would simply read all the first words into a vector (so you know the size).
std::string line
std::getline(file, line); // Ignore the first line.
std::string word
while(file >> word) {
names.push_back(word);
std::getline(file, line); // ignore the rest of the line.
}
We could get fancy. Use iterators to simply create the array directly.
class Line
{
std::string firstWord;
friend std::istream& operator>>(std::istream& stream, Line& data) {
stream >> data.firstWord;
stream.ignore(std::numeric_limits<std::streamsize>::max(), '\n'); retrun stream;
}
operator std::string() const {
return firstWord;
}
};
Now you can create and load the vector in one line:
std::vector<std::string> names(std::istream_iterator<Line>(file),
std::istream_iterator<Line>{});
Then finally copy the names out can be made easier using foreach loop. Also don't use std::endl in a loop like this. It forces a flush of the underlying bugger after each new line. This is very ineffecient.
for(auto const& name: names) {
std::cout << name << "\n";
}
So the result is:
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <iterator>
#include <algorithm>
class Line
{
std::string firstWord;
friend std::istream& operator>>(std::istream& stream, Line& data) {
stream >> data.firstWord;
stream.ignore(std::numeric_limits<std::streamsize>::max(), '\n'); return stream;
}
operator std::string() const {
return firstWord;
}
};
int main()
{
std::ifstream file("names.txt");
std::string line
std::getline(file, line); // Ignore the first line.
std::vector<std::string> names(std::istream_iterator<Line>(file),
std::istream_iterator<Line>{});
random_shuffle(std::begin(names), std::end(names));
for(auto const& name: names) {
std::cout << name << "\n";
}
}
I have following C++ object
std::vector<std::vector<SomeClass>> someClassVectors(sizeOFOuter);
where I know the size of "outer" vector, but sizes of "inner" vectors varies. I need to copy the elements of this structure into 1D array like this:
SomeClass * someClassArray;
I have a solution where I use std::copy like this
int count = 0;
for (int i = 0; i < sizeOfOuter; i++)
{
std::copy(someClassVectors[i].begin(), someClassVectors[i].end(), &someClassArray[count]);
count += someClassVectors[i].size();
}
but the class includes large matrices which means I cannot have the "vectors" structure and 1D array allocated twice at the same time.
Any ideas?
Do you previously preallocate someClassArray to a given size? I'd suggest using 1D vector for getting rid of known problems with the plain array if possible.
what about something like this:
#include <iostream>
#include <vector>
#include <algorithm>
#include <iterator>
int main() {
std::vector<std::vector<int>> someClassVectors {
{1,2,3},
{4,5,6},
{7,8,9}
};
std::vector<int> flat;
while (!someClassVectors.empty())
{
auto& last = someClassVectors.back();
std::move(std::rbegin(last), std::rend(last), std::back_inserter(flat));
someClassVectors.pop_back();
}
std::reverse(std::begin(flat), std::end(flat));
int * someClassArray = flat.data();
std::copy(someClassArray, someClassArray + flat.size(), std::ostream_iterator<int>(std::cout, " "));
}
The extra reverse operation doesn't have an effect on memory metrics - such an approach helps to avoid unneeded memory reallocations resulting from removing vector elements from beginning to end.
EDIT
Inspired by comments I changed copy to move semantics
Embrace Range-v3 (or whatever will be introduced in C++20) and write a solution in (almost) a single line:
auto flattenedRange = ranges::views::join(someClassVectors);
this gives you a range in flattenedRange, which you can loop over or copy somewhere else easily.
This is a possible use case:
#include <iostream>
#include <vector>
#include <range/v3/view/join.hpp>
int main()
{
std::vector<std::vector<int>> Ints2D = {
{1,2,3},
{4},
{5,6}
};
auto Ints1D = ranges::views::join(Ints2D);
// here, going from Ints1D to a C-style array is easy, and shown in the other answer already
for (auto const& Int : Ints1D) {
std::cout << Int << ' ';
}
std::cout << '\n';
// output is: 1 2 3 4 5 6
}
In case you want to get a true std::vector instead of a range, before writing it into a C-style array, you can include this other header
#include <range/v3/range/conversion.hpp>
and pipe join's output into a conversion function:
auto Ints1D = ranges::views::join(Ints2D) | ranges::to_vector;
// auto deduces std::vector<int>
In terms of standard and versions, it doesn't really require much. In this demo you can see that it compiles and runs just fine with
compiler GCC 7.3
library Range-v3 0.9.1
C++14 standard (option -std=c++14 to g++)
As regards the copies
ranges::views::join(Ints2D) is only creating a view on Ints2D, so no copy happens; if view doesn't make sense to you, you might want to give a look at Chapter 7 from Functional Programming in C++, which has a very clear explanation of ranges, with pictures and everything;¹
even assigning that output to a variable, auto Ints1D = ranges::views::join(Ints2D);, does not trigger a copy; Ints1D in this case is not a std::vector<int>, even though it behaves as one when we loop on it (behaves as a vector because it's a view on it);
converting it to a vector, e.g. via | ranges::to_vector, obviously triggers a copy, because you are no more requesting a view on a vector, but a true one;
passing the range to an algorithm which loops on its elements doesn't trigger a copy.
Here's an example code that you can try out:
// STL
#include <iostream>
#include <vector>
// Boost and Range-v3
#include <boost/range/algorithm/for_each.hpp>
#include <range/v3/view/join.hpp>
#include <range/v3/range/conversion.hpp>
struct A {
A() = default;
A(A const&) { std::cout << "copy ctor\n"; };
};
int main()
{
std::vector<std::vector<A>> Ints2D = {
{A{},A{}},
{A{},A{}}
};
using boost::range::for_each;
using ranges::to_vector;
using ranges::views::join;
std::cout << "no copy, because you're happy with the range\n";
auto Ints1Dview = join(Ints2D);
std::cout << "copy, because you want a true vector\n";
auto Ints1D = join(Ints2D) | to_vector;
std::cout << "copy, despite the refernce, because you need a true vector\n";
auto const& Ints1Dref = join(Ints2D) | to_vector;
std::cout << "no copy, because we movedd\n";
auto const& Ints1Dref_ = join(std::move(Ints2D)) | to_vector;
std::cout << "no copy\n";
for_each(join(Ints2D), [](auto const&){ std::cout << "hello\n"; });
}
¹ In an attempt to try giving a clue of what a range is, I would say that you can imagine it as a thing wrapping two iterators, one poiting to the end of the range, the other one pointing to the begin of the range, the latter being incrementable via operator++; this opearator will take care of the jumps in the correct way, for instance, after viewing the element 3 in Ints2D (which is in Ints2D[0][2]), operator++ will make the iterator jump to view the elment Ints[1][0].
I need a create array in c++ but I need array always with variables name
int Magic(string name_array,int n)
{
string Name = "Something";
Name.append(name_array);
double * Name = new double[n];
}
int main()
{
Magic("a.txt",10);
}
And I have this error:
operator' : 'identifier1' differs in levels of indirection from 'identifier2'
I know it's not a python but maybe a map help me? How I can make this?
If you want to be able to access different arrays by string names, consider using a std::map<std::string, std::vector<double>>. This maps strings to C++'s better, more dynamic answer to arrays. In this case your code would be something like:
#include <iostream>
#include <map>
#include <vector>
void AddVector(std::map<std::string, std::vector<double>> &io_map,
const std::string& i_name,
const std::size_t i_size)
{
io_map[i_name].resize(i_size);
}
int main()
{
std::map<std::string, std::vector<double>> vector_map;
AddVector(vector_map, "Vector1", 3);
AddVector(vector_map, "Vector2", 10);
std::cout << "Vector with string key Vector1 has size: " << vector_map["Vector1"].size() << std::endl;
return 0;
}
In this code I've tried to be as close to the code you've given - resizing the vectors to the size you would have created the array in your "Magic" function. However, vectors can dynamically resize, so you may not even need to create/resize them in your code depending on your use case.
I want to know how I can assign multiple values to a vector at once:
#include <iostream>
#include <boost/numeric/ublas/vector.hpp>
#include <boost/numeric/ublas/io.hpp>
using namespace boost::numeric::ublas;
int main()
{
vector<double> v1(3);
v1(0)=0;
v1(1)=0.1;
v1(2)=0.05;
v1(3)=0.25;
return 0;
}
I want to assign all the values at once.
something like:
v1 << 0,0.1,0.05,0.25;
I tried operator += and there is an error, but I think operator += works for std::vector not boost::....vector
Take a look at documentation examples http://svn.boost.org/svn/boost/trunk/libs/numeric/ublas/doc/samples/assignment_examples.cpp
Basically, you need v1 <<= 0, 1, 2;, see more examples in the docs. Unfortunately this library doesn't support initializer_list's yet: http://boost.2283326.n4.nabble.com/Initializing-from-an-initializer-list-td4647029.html
This prints the address for my string, but not its' contents,
#include <memory>
#include <string>
#include <list>
#include <iostream>
#include <iterator>
using namespace std;
int _tmain(int argc, _TCHAR* argv[])
{
unique_ptr<list<shared_ptr<string>>> upList (new list<shared_ptr<string>>);
shared_ptr<string> spNation (new string ("India"));
upList->push_back (spNation);
copy (upList->begin(), upList->end(), ostream_iterator<shared_ptr<string>> (cout, "\n "));
return 0;
}
My questions are:
What ostream_iterator<shared_ptr<string>> is taking shared_ptr or strings as its' prime object.
How to print actual string contents (i.e. India) using this approach.
Is this approach is preferable over traditional for loop to print all node contents.
What ostream_iterator<shared_ptr<string>> is taking shared_ptr or strings as its' prime object.
You've instantiated ostream_iterator for shared_ptr<string>, so that is what it will attempt to output.
How to print actual string contents (i.e. India) using this approach.
If you really want to use shared pointers for some reason, then you can't use copy since that won't undo the extra level of indirection. Either use a plain loop, or get rid of the unnecessary indirection:
list<string> list;
list.push_back("India");
copy(list.begin(), list.end(), ostream_iterator<string>(cout, "\n "));
Of course, it doesn't look as exciting without all the arrows, templates, new-expressions and pseudohungarian warts, but anyone trying to maintain the code won't thank you for adding such embellishments.
Is this approach is preferable over traditional for loop to print all node contents
It's preferable when it makes the code simpler. When it doesn't, it isn't.
Firstly: why you use shared_ptr<string> instead of string here? You shouln't do this.
1)
shared_ptr<string>
2) Use std::for_each with lambda (or range-based for loop)
for_each(upList->begin(), upList->end(), [](const shared_ptr<string>& p)
{
cout << *p << endl;
});
or
for (const auto& p : upList)
{
std::cout << *p << std::endl;
}