Build Map With For Loop - c++

I am trying to add values to a map variable that takes int keys and char values. The map is to contain the positions of letters in the alphabet, and the corresponding letter at that position. For some reason, I am getting an error from the .insert() portion inside the for loop.
map<int, char> cipher;
for (int i = 0; i < 26; i++)
{
cipher.insert(i, char(97 + i));
}

Here is the correct syntax when using a map:
for (int i = 0; i < 26; i++)
{
cipher[i] = char(97 + i);
}
//To use it
std::cout << cipher[letterindex] << std::endl;

I would do it slightly different:
I will use map::emplace instead as it inserts a new element into the container which is constructed in-place with the given args(if it's not already there) and avoid unnecessary copy or move operations if possible.
for (int i = 0; i < 26; i++)
{
cipher.emplace(i, char(97 + i));
}
try it -> https://ideone.com/pKf99l
http://en.cppreference.com/w/cpp/container/map/emplace

You should use std::make_pair:
for (int i = 0; i < 26; i++)
{
cipher.insert(std::make_pair(i, char(97 + i)));
}
More details here:
http://en.cppreference.com/w/cpp/container/map/insert
http://en.cppreference.com/w/cpp/utility/pair/make_pair
The problem is there is no overload of the insert functions that takes separate key/value arguments.

Related

C++ STL Map : Map.count(element) takes less time than Map[element]

I was trying this problem on leetcode,
https://leetcode.com/problems/naming-a-company/description/ .
I've observed the following
My Code :
long long distinctNames(vector<string>& ideas) {
unordered_map<string,bool> isPresent;
vector<vector<long long>> dp(26,vector<long long>(26,0));
int n = ideas.size();
long long ans = 0;
for(int i = 0; i < n; i++)
isPresent[ideas[i]] = true;
for(int i = 0; i < n; i++)
{
char x = ideas[i][0];
string ts = ideas[i];
for(int j = 0; j < 26; j++)
{
char y = 'a' + j;
ts[0] = y;
if(!isPresent[ts])
dp[x-'a'][j]++;
}
}
for(int i = 0; i < 26; i++)
{
for(int j = 0; j < 26; j++)
{
if(i==j) continue;
ans += (dp[i][j] * dp[j][i]);
}
}
return ans;
}
This code was getting TLE (85/89).
But, in the same code, if I replace
!isPresent[ts]
with
!isPresent.count(ts)
Same code runs much faster and passes.
Anyone can explain why ?
isPresent[ts] returns a reference to a map value object (so you can write isPresent[ts] = something. So if ts is not present in the map, then isPresent[ts] must default construct a map entry so that it has something to return a reference to. This is the reason that map::operator[] is not const.
isPresent.count(ts) has no such problems. If the ts key is not present then the map is unchanged.
operator[] on std::unordered_map inserts a default constructed element if none is yet present (which is also why the operator doesn't work on a const object.) Insertion potentially requires allocating memory or other somewhat slow things. Calling count does not, nor would e.g. find.

C++ Convert one exact string element into an int

I want to create a string array and then after writing lines into it I want to change one exact character into int. I already know that all the characters are going to be numbers. As my goal is to change the one character at a time, options like atoi, stoi etc. are perhaps off? The closest I got is that:
#include <iostream>
int main()
{
int n=0,suma=0,i=0;
int multiplier[11]={1,3,7,9,1,3,7,9,1,3,1};
std::cin>>n;
std::string str[n];
for (int i = 0; i < n; ++i)
{
std::cin>>str[i];
}
for (int i = 0; i < n; ++i)
{
for (int j = 0; j < 11; ++j)
{
i = str[i][j] - '0';
std::cout << i;
}
}
}
Although this is the output I get
"1-48"
I know that the string is going to be 11 characters long. Any ideas?
EDIT: It was a single typo that caused my confuse :p Yet still I'm looking forward to read and learn from your suggestions such as using different way to read n (from user input) strings. :)
In your loop:
for (int i = 0; i < n; ++i)
{
for (int j = 0; j < 11; ++j)
{
i = str[i][j] - '0';
std::cout << i;
}
}
you are modifying outer loop variable i (looks like for the purpose of printing a value).
Given an unfortunate input, you would go out-of-bounds fast.

c++ vector clear() doen't work

string str;
vector<int> v(200,0);
getline(cin, str);
for (int i = 0 ; i < str.size(); i++) {
v[str[i]-97]++;
}
for (int i = 0; i < 26; i++) {
printf("%d ", v[i]);
}
v.clear();
cout << endl;
for (int i = 0; i < 26; i++) {
printf("%d ", v[i]);
}
I want to know the number of each alphabet and clear vector v. But it doesn't work. what is the reason?
Calling v.clear() resizes the vector to zero elements. If you want to set the elements to a specific value (here 0), keeping the original size, you may use
v.assign(v.size(), 0);
Change the last for loop to :
for (int i = 0; i < v.size(); i++) {
printf("%d ", v[i]);
}
You're clearing your vector, removing all elements and then you seem to be trying to loop through it's first 25 elements, even though it's empty.
The reason you're throwing std_out_of_range is because you're trying to access elements where they don't exist.
You should pretty much never loop through something through an already set number of times if you can't ensure that the vector in question won't have that many elements.
If you absolutely have to loop through your vector a set number of times, at least ensure that your vector will have that many elements first.
if (v.size() >= 25)
{
for (int i = 0; i <= 25; i++)
{
printf("%d ", v[i]);
}
}
In this case your vector will most definitely not have 25 elements since you cleared your vector prior to the loop, but it's much more safe.

Non-Space delimited text file to 2D vector

I've got a file that can be of any size and is a series of char values without any spaces between (except a blank space is treated as a blank cell of a grid).
xxxxxxx
xx xx
xxyyyxx
After some great help I've gone with the method to use a vector<vector<char> > however I cannot seem to populate it.
void readCourse(istream& fin) {
// using 3 and 7 to match example shown above
vector<vector<char> > data(3, vector<char>(7));
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 7; j++) {
fin.get(data[i][j]); // I believe the problem exists here
} // Does the .get() method work here?
} // Or does it need to be .push_back()?
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 7; j++) {
cout << data[i][j];
}
}
}
Is my method for populating my 2D vector valid? If not, can you please point me in the right direction?
I'd keep it simple and efficient with a single vector<char>:
vector<char> readCourse(istream& fin) {
vector<char> course(3*(7+2)); // 3x7 plus newlines
fin.read(course.data(), course.size());
course.resize(fin.gcount());
auto end = remove(course.begin(), course.end(), '\n');
end = remove(course.begin(), end, '\r');
course.erase(end, course.end()); // purge all \n and \r
return course;
}
That's a single input operation to get all the data, followed by removing the characters you don't need. You can then access the result in a 2D way like this:
course.at(x + y*7) // assuming width 7
That may seem a bit inconvenient, but it is efficient and compact--the overhead is always three pointers and a single heap allocation, instead of being proportional to the number of rows.
Solution I ended up using after ADT implementation:
void readCourse(std::istream& fin) {
std::vector<std::string> level
std::string line;
while(std::getline(fin, line) {
level.push_back(line);
}
for (std::size_t i = 0; i < 3; i++) {
for (std::size_t j = 0; j < 7; j++) {
std::cout << data[i][j];
}
std::cout << std::endl;
}
}

Intersection of 2 dynamically allocated arrays c++

I am trying to create a function that will find the intersection of two dynamically allocated arrays comparing array 1 to array 2. For any values in array 1 that are not in array 2, those values should be deleted in array 1 so that array 1 now only holds the common values of both arrays (no repeats). I cannot use vectors, hashes, or any other thing outside of my current functions in my class:
here is my code so far:
bool IntSet::contains(int val) const
{
for (int i = 0; i < numValues; i++)
{
if (set[i] == val)
return true;
}
return false;
}
this function compares an integer parameter to values currently stored in the array...if a value is in the array it returns true and if else false;
this next function takes in a value and removes that value from the array:
void IntSet::remove(int val)
{
for (int i = 0; i < numValues; i++)
{
if (set[i] == val)
for (int j = 0; j < numValues; j++)
set[j] = set[j + 1];
}
numValues--;
}
here's where I've been having problems, this next function is supposed to iterate through one array and compare those values with the values in the other array...if one value from one array is in the other, it should just skip it, but if a value is not in the array calling the function, it should delete that value from the calling array:
void IntSet::removeDifferent(const IntSet &set2)
{
for (int i = 0; i < set2.size(); i++)
{
if (!set2.contains(set[i]))
{
remove(set[i]);
}
}
}
ive tried about 50 different variations on the removeDifferent() function and I just can't seem to figure this one out. Could someone point me in the right direction?
You're iterating i through the indexes of set2, but then you're testing set[i]. Try this:
void IntSet::removeDifferent(const IntSet &set2)
{
for (int i = 0; i < numValues; ) {
if (!set2.contains(set[i])) {
remove(set[i]);
} else {
i++;
}
}
Note that I also removed i++ from the for loop header. This is because when you remove an element, all the following elements are shifted down, so the next element takes its place in the array. If you incremented i, it would skip that element.
You also need to fix remove. It should start its inner loop from i, so it only shifts down the elements after the one being removed, and it should stop at numValues-1, so it doesn't try to access outside the array when it copies set[j+1]. And as an optimization, it can break out of the outer loop once it has found a match (I assume IntSet doesn't allow duplicates, since you only decrement numValues by 1).
void IntSet::remove(int val)
{
for (int i = 0; i < numValues; i++)
{
if (set[i] == val) {
for (int j = i; j < numValues - 1; j++) {
set[j] = set[j + 1];
}
break;
}
}
numValues--;
}
Your problem is in your remove() function:
void IntSet::remove(int val)
{
for (int i = 0; i < numValues; i++)
{
if (set[i] == val)
for (int j = 0; j < numValues; j++)
set[j] = set[j + 1];
}
numValues--;
}
You can figure out yourself why this is wrong by using a paper and pencil here. Start with a typical example: let's say you found the value you're looking for in the third element of a five-element array:
if (set[i] == val)
In this example, i would be set to 2, and numValues would be set to five. It doesn't matter what val is. Whatever it is, you found it when i is 2, and numValues is five: you found it in the third element of a five element array. Keep that in mind.
Now, you know that you are now supposed to remove the third element in this five element array. But what do you think will happen next:
for (int j = 0; j < numValues; j++)
set[j] = set[j + 1];
Well, using the aforementioned paper and pencil, if you work it out, the following will happen:
set[1] will be copied to set[0]
set[2] will be copied to set[1]
set[3] will be copied to set[2]
set[4] will be copied to set[3]
set[5] will be copied to set[4]
There are two problems here:
A) There is no set[5]. Recall that this is a five-element array, si you only have set[0] through set[4]
B) You're not supposed to copy everything in array down to one element. You have to copy only the elements after the element you want to remove.
Fix these two problems, and you will probably find that everything will work correctly.