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

  2. Rahul Mathur

    Ian Collins Guest

    You really shouldn't be using a zero size array here, it isn't valid C++
    and certainly isn't what you want.
    Not a very good name for a std::map, which is ordered!
    Missing namespace?
    Missing semicolon.
    This next section shouldn't be inside the while loop! You are printing
    the map each time you add to it.
    To here.
     
    Ian Collins, Jan 18, 2014
    #2
    1. Advertisements

  3. Oh, hi!

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

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

    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.

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

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

    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?

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

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

    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 (Text):

    #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

    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?
     
    Rahul Mathur, Jan 20, 2014
    #5
  6. Rahul Mathur

    Ian Collins Guest

    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, Jan 20, 2014
    #6
  7. Rahul Mathur

    Jorgen Grahn Guest

    Well, or Perl.
    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.
    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, Jan 20, 2014
    #7
  8. Rahul Mathur

    Jorgen Grahn Guest

    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, Jan 20, 2014
    #8
  9. Rahul Mathur

    woodbrian77 Guest

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

    Brian
    Ebenezer Enterprises -
    http://webEbenezer.net
     
    woodbrian77, Jan 20, 2014
    #9
  10. OT, but let me correct some obvious errors:

    perl -nl -aF'\|' -e 'print "$F[0] $F[6]"; exit if $.>2;'
     
    Seungbeom Kim, Jan 21, 2014
    #10
    1. Advertisements

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 (here). After that, you can post your question and our members will help you out.