STL::MAP: Printing values only once ..

R

Rahul Mathur

Hi,

I have a input.txt file separator by pipe '|' as -

40147|181|ORANGE|MIKE|XX||1000397900|3500
40148|373|ORANGE|BOB|XX||1078889400|4500
40149|673|ORANGE|TREY|XX||1095159900|5500


I only wish to have all the FIRST(ID=40147) and LAST FIELD(PRICE=3500) to be printed for three lines as given above.

I am reading as -

--
#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
#include <boost/algorithm/string.hpp>

using namespace std;

struct FILE_INPUT {
int ID;
int Asset_ID;
char T_Name[];
char Symbol[];
char Series[];
char Gap;
int Date;
int price;
};


int main() {

typedef std::map<int, int> unordmap;
unordmap ask;

FILE_INPUT fl_inp;
memset( &fl_inp, 0, sizeof(fl_inp) );
ifstream in ("input.txt");
string s;

const char delimiter = '|';
while ( getline (in, s) ) {
trim( s );
if ( !s.empty() ) {
stringstream strm( s );
string item;
getline( strm, item );
stringstream stra( item );
string tmp;
getline( stra, tmp, delimiter );
{
stringstream strb( tmp );
strb >> fl_inp.ID;
}
getline( stra, tmp, delimiter )
{
stringstream strb( tmp );
strb >> fl_inp.price;
}

ask.insert( std::make_pair((fl_inp.ID),(fl_inp.price)) );
unordmap::iterator pos = ask.begin();
for (pos = ask.begin(); pos != ask.end(); ++pos) {
std::cout << "ID: " << pos->first << "\t"
<< "Price: " << pos->second << std::endl;
}
std::cout << " " << endl;
}
}
}
--

The map is being inserted with both ID as key and price as value but while printing it prints the values thrice as -

ID: 40147 Price: 3500

ID: 40147 Price: 4500
ID: 40148 Price: 5500

ID: 40147 Price: 3500
ID: 40148 Price: 4500
ID: 40149 Price: 5500

The MAP should print all values together only once as -

ID: 40147 Price: 3500
ID: 40148 Price: 4500
ID: 40149 Price: 5500
 
I

Ian Collins

Rahul said:
Hi,

I have a input.txt file separator by pipe '|' as -

40147|181|ORANGE|MIKE|XX||1000397900|3500
40148|373|ORANGE|BOB|XX||1078889400|4500
40149|673|ORANGE|TREY|XX||1095159900|5500


I only wish to have all the FIRST(ID=40147) and LAST FIELD(PRICE=3500) to be printed for three lines as given above.

I am reading as -

--
#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
#include <boost/algorithm/string.hpp>

using namespace std;

struct FILE_INPUT {
int ID;
int Asset_ID;
char T_Name[];

You really shouldn't be using a zero size array here, it isn't valid C++
and certainly isn't what you want.
char Symbol[];
char Series[];
char Gap;
int Date;
int price;
};


int main() {

typedef std::map<int, int> unordmap;

Not a very good name for a std::map, which is ordered!
unordmap ask;

FILE_INPUT fl_inp;
memset( &fl_inp, 0, sizeof(fl_inp) );
ifstream in ("input.txt");
string s;

const char delimiter = '|';
while ( getline (in, s) ) {
trim( s );

Missing namespace?
if ( !s.empty() ) {
stringstream strm( s );
string item;
getline( strm, item );
stringstream stra( item );
string tmp;
getline( stra, tmp, delimiter );
{
stringstream strb( tmp );
strb >> fl_inp.ID;
}
getline( stra, tmp, delimiter )

Missing semicolon.
{
stringstream strb( tmp );
strb >> fl_inp.price;
}

ask.insert( std::make_pair((fl_inp.ID),(fl_inp.price)) );

This next section shouldn't be inside the while loop! You are printing
the map each time you add to it.
unordmap::iterator pos = ask.begin();
for (pos = ask.begin(); pos != ask.end(); ++pos) {
std::cout << "ID: " << pos->first << "\t"
<< "Price: " << pos->second << std::endl;
}
std::cout << " " << endl;

To here.
 
A

Alf P. Steinbach


Oh, hi!

I have a input.txt file separator by pipe '|' as -

40147|181|ORANGE|MIKE|XX||1000397900|3500
40148|373|ORANGE|BOB|XX||1078889400|4500
40149|673|ORANGE|TREY|XX||1095159900|5500


I only wish to have all the FIRST(ID=40147) and LAST FIELD(PRICE=3500) to
be printed for three lines as given above.

I think this would be a task for "awk", or its modern replacement if
there is one. But as I recall from old days, "awk" was good at splitting
lines into fields. If working in Windows, then there are lots of "Unix
utilities" around, including just installing Cygwin (one practical idea
is to map drive U: to such utilities, write "u::awk").

I am reading as -

--
#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
#include <boost/algorithm/string.hpp>

Using Boost is generally a good idea when you have it available, but in
this case I think it's shooting gnats with intercontinental ballistic
H-bomb missiles. Will kill them gnats, guaranteed, yes. But, overkill...

using namespace std;

struct FILE_INPUT {

It's a good idea to reserve ALL UPPERCASE for macro names.

That way you tend to avoid name collisions and unintended text
substitutions.

Conversely, it's not a good idea to use ALL UPPERCASE for anything else
-- in C and C++.

Java and C# conventions are a different matter, since neither Java nor
C# has a preprocessor.

It's quite a bit ironic in a way. Java got its convention for constants
from C, where constants had to be defined as macros, hence ALL
UPPERCASE. So the Java convention is really about using ALL UPPERCASE
for macros-that-denote-constants, but Java doesn't have a preprocessor,
and does have a facility for defining constants, so it's all misplaced.


Again, ungood ALL UPPERCASE name.

int Asset_ID;
char T_Name[];

Oh noes, that won't work! In standard C++ an array must have a specified
size. And unless it's dynamically allocated, size must be >0.

This shouldn't compile with strict ISO compliance.

An alternative for unknown-string-size is to use a `std::string`.

char Symbol[];
char Series[];
char Gap;
int Date;
int price;
};


int main() {

typedef std::map<int, int> unordmap;
unordmap ask;

FILE_INPUT fl_inp;
memset( &fl_inp, 0, sizeof(fl_inp) );

Oh! `memset`, that's easy to get wrong, and needlessly verbose.

In standard C++ just do

FILE_INPUT fl_inp = {};

to zero it.

See, it's safer, speedier, and shorter... ;-)

ifstream in ("input.txt");
string s;

const char delimiter = '|';
while ( getline (in, s) ) {
trim( s );

I do not see where you get that unqualified `trim` function from, but
perhaps Boost (formally incorrect) defines it in the `std` namespace so
that it's found by argument dependent lookup?

if ( !s.empty() ) {
stringstream strm( s );
string item;
getline( strm, item );

This reads the whole line from the stream. And the whole line is all
there is. What is the purpose of that?

stringstream stra( item );
string tmp;
getline( stra, tmp, delimiter );
{
stringstream strb( tmp );
strb >> fl_inp.ID;
}
getline( stra, tmp, delimiter )
{
stringstream strb( tmp );
strb >> fl_inp.price;
}

Presumably the above code is what remained after you removed error
checking etc., so as to get simpler code for presentation here?

ask.insert( std::make_pair((fl_inp.ID),(fl_inp.price)) );
unordmap::iterator pos = ask.begin();
for (pos = ask.begin(); pos != ask.end(); ++pos) {
std::cout << "ID: " << pos->first << "\t"
<< "Price: " << pos->second << std::endl;
}
std::cout << " " << endl;
}
}
}

Consider something like this (it differs from yours in not verifying
that the strings are valid number specifications, but you can just add
that):


Code:
#include <algorithm>        // std::replace
#include <iostream>
#include <map>              // std::map
#include <sstream>          // std::istringstream
#include <stdlib.h>         // EXIT_FAILURE
#include <string>           // std::string
using namespace std;

#define ITEMS_OF( c ) c.begin(), c.end()

auto main()
-> int
{
string line;
while( getline( cin, line ) )
{
replace( ITEMS_OF( line ), '|', ' ' );
istringstream stream( line );
for( int i = 1;  i <= 7;  ++i )
{
string word;
if( (stream >> word).fail() )
{
cout << endl;
cerr << "! Not enough items on this input line:" << endl;
cerr << "! '" << line << "'" << endl;
return EXIT_FAILURE;
}
if( i == 1 ) { cout << "ID: " << word << " "; }
if( i == 7 ) { cout << "Price: " << word << endl; }
}
}
}


Cheers & hth.,

- Alf
 
R

Rahul Mathur

Hi,



I have a input.txt file separator by pipe '|' as -



40147|181|ORANGE|MIKE|XX||1000397900|3500

40148|373|ORANGE|BOB|XX||1078889400|4500

40149|673|ORANGE|TREY|XX||1095159900|5500





I only wish to have all the FIRST(ID=40147) and LAST FIELD(PRICE=3500) to be printed for three lines as given above.



I am reading as -



--

#include <iostream>

#include <fstream>

#include <sstream>

#include <string>

#include <boost/algorithm/string.hpp>



using namespace std;



struct FILE_INPUT {

int ID;

int Asset_ID;

char T_Name[];

char Symbol[];

char Series[];

char Gap;

int Date;

int price;

};





int main() {



typedef std::map<int, int> unordmap;

unordmap ask;



FILE_INPUT fl_inp;

memset( &fl_inp, 0, sizeof(fl_inp) );

ifstream in ("input.txt");

string s;



const char delimiter = '|';

while ( getline (in, s) ) {

trim( s );

if ( !s.empty() ) {

stringstream strm( s );

string item;

getline( strm, item );

stringstream stra( item );

string tmp;

getline( stra, tmp, delimiter );

{

stringstream strb( tmp );

strb >> fl_inp.ID;

}

getline( stra, tmp, delimiter )

{

stringstream strb( tmp );

strb >> fl_inp.price;

}



ask.insert( std::make_pair((fl_inp.ID),(fl_inp.price)) );

unordmap::iterator pos = ask.begin();

for (pos = ask.begin(); pos != ask.end(); ++pos) {

std::cout << "ID: " << pos->first << "\t"

<< "Price: " << pos->second << std::endl;

}

std::cout << " " << endl;

}

}

}

--



The map is being inserted with both ID as key and price as value but while printing it prints the values thrice as -



ID: 40147 Price: 3500



ID: 40147 Price: 4500

ID: 40148 Price: 5500



ID: 40147 Price: 3500

ID: 40148 Price: 4500

ID: 40149 Price: 5500



The MAP should print all values together only once as -



ID: 40147 Price: 3500

ID: 40148 Price: 4500

ID: 40149 Price: 5500



--



Can I maintain some checks to print all values simply once.



Thanks.

Thanks ALL, for correcting the correct way of calling make_pair() and latter printing out the contents after the loop.
 
R

Rahul Mathur

If I need to print FIRST, FOURTH and SIXTH field only related to third row TREY only.

How can I modify above code?
 
I

Ian Collins

Rahul said:
If I need to print FIRST, FOURTH and SIXTH field only related to third row TREY only.

How can I modify above code?

Parse the rest of the fields and print them... Have a go and post your
code. If you do, please clean up the mess that shite google interface
will make of your code.

There wasn't any "above code" because you have top-posted :)
 
J

Jorgen Grahn

In this case, the modern replacement of awk is ..... awk.

Well, or Perl.
Above requirement can be met with

awk -d'|' '{print $1, $7}'

There was a "for three lines" requirement too, but it can be met by
piping things through 'sed 3q'. Or Perl, or possibly Awk itself.
which is more or less guarenteed to be simpler than any C++ program doing
the same task. :)

Yes. And next best is a C++ program using the same approach.
I got the impression that the original sucked up the whole input file
before extracting the information it wanted; that's slower and IME
more troublesome (harder to report syntax errors and so on).

I didn't read the original carefully though.

/Jorgen
 
J

Jorgen Grahn

AFAIK splitting a string is still not in the standard library, so any C++
solution is not as simple as a language that has a split/explode. (Please
correct me if I'm wrong!)

I expect <regex> to have such things, but haven't checked. I keep my
own string splitter and some of the other Perl things I use the most,
e.g. 'while(<>)'.

Anyway, my comment above was not really about split; more about the
idiom of line-by-line text filters, versus pulling it all into some
data structure and /then/ processing it.

/Jorgen
 
S

Seungbeom Kim

The Perl equivalent:

perl -p -F'|' -e 'print "$F[0] $F[6]"; exit if $.>2;'

OT, but let me correct some obvious errors:

perl -nl -aF'\|' -e 'print "$F[0] $F[6]"; exit if $.>2;'
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Similar Threads


Members online

No members online now.

Forum statistics

Threads
473,744
Messages
2,569,482
Members
44,901
Latest member
Noble71S45

Latest Threads

Top