STL::MAP: Printing values only once ..

Discussion in 'C++' started by Rahul Mathur, Jan 18, 2014.

  1. Rahul Mathur

    Rahul Mathur Guest

    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.
    Rahul Mathur, Jan 18, 2014
    #1
    1. Advertising

  2. Rahul Mathur

    Ian Collins Guest

    Rahul Mathur wrote:
    > 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.

    > }
    > }
    > }
    >



    --
    Ian Collins
    Ian Collins, Jan 18, 2014
    #2
    1. Advertising

  3. On 18.01.2014 03:39, Rahul Mathur wrote:
    > Hi,


    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.


    > int ID;


    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
    Alf P. Steinbach, Jan 18, 2014
    #3
  4. Rahul Mathur

    Rahul Mathur Guest

    On Saturday, January 18, 2014 8:09:21 AM UTC+5:30, Rahul Mathur wrote:
    > 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.
    Rahul Mathur, Jan 18, 2014
    #4
  5. Rahul Mathur

    Rahul Mathur Guest

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

    How can I modify above code?



    On Saturday, January 18, 2014 8:09:21 AM UTC+5:30, Rahul Mathur wrote:
    > 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.
    Rahul Mathur, Jan 20, 2014
    #5
  6. Rahul Mathur

    Ian Collins Guest

    Rahul Mathur wrote:
    > 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 :)

    --
    Ian Collins
    Ian Collins, Jan 20, 2014
    #6
  7. Rahul Mathur

    Jorgen Grahn Guest

    On Sun, 2014-01-19, Martijn Lievaart wrote:
    > On Sat, 18 Jan 2014 04:24:27 +0100, Alf P. Steinbach wrote:
    >
    >> On 18.01.2014 03:39, Rahul Mathur wrote:
    >>> Hi,

    >>
    >> 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").

    >
    > 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

    --
    // Jorgen Grahn <grahn@ Oo o. . .
    \X/ snipabacken.se> O o .
    Jorgen Grahn, Jan 20, 2014
    #7
  8. Rahul Mathur

    Jorgen Grahn Guest

    On Mon, 2014-01-20, Martijn Lievaart wrote:
    > On Mon, 20 Jan 2014 17:01:36 +0000, Jorgen Grahn wrote:

    ....
    >>> 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).

    >
    > 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

    --
    // Jorgen Grahn <grahn@ Oo o. . .
    \X/ snipabacken.se> O o .
    Jorgen Grahn, Jan 20, 2014
    #8
  9. Rahul Mathur

    Guest

    On Friday, January 17, 2014 9:24:27 PM UTC-6, Alf P. Steinbach wrote:
    >
    >
    > Using Boost is generally a good idea when you have it available,


    I wouldn't go that far, but I do think parts of
    Boost are great.

    Brian
    Ebenezer Enterprises -
    http://webEbenezer.net
    , Jan 20, 2014
    #9
  10. On 2014-01-20 11:22, Martijn Lievaart wrote:
    > 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;'

    --
    Seungbeom Kim
    Seungbeom Kim, Jan 21, 2014
    #10
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Marcus
    Replies:
    2
    Views:
    577
    Marcus
    Dec 9, 2005
  2. Replies:
    2
    Views:
    539
    klaus hoffmann
    Feb 22, 2006
  3. Eric Layman
    Replies:
    3
    Views:
    393
    Damien
    Apr 2, 2007
  4. kl
    Replies:
    7
    Views:
    1,270
    James Kanze
    Jan 1, 2008
  5. Luca Risolia

    STL map to STL vector

    Luca Risolia, Jan 13, 2014, in forum: C++
    Replies:
    32
    Views:
    333
    Seungbeom Kim
    Jan 18, 2014
Loading...

Share This Page