How to get a row friom a txt-file into BTreeMap

// use std::str::FromStr;
use rev_lines::RevLines;
use std::io::BufReader;
use std::fs::File;

fn main() {
    // Haal de laatste regel uit invoer bestand
    let log_file = File::open("/mnt/Data/Coins/Bittrex_invoer_rs.txt").unwrap();
    let rev_lines = RevLines::new(BufReader::new(log_file)).unwrap();
    let n_last_lines = 1;   // We want to display the last line (5 = the last 5 lines)

    let mut lines: Vec<String> = Vec::new();
    let mut counter = 0;
    for line in rev_lines {
        if counter >= n_last_lines {
            break;
        }
        counter = counter + 1;
        lines.push(line);
        // lines.push(String::from_str(&line));
    }
    for line in lines.iter().rev() {
        println!("Row 23: {}", line);
/*
This prints: Row 23: [("USD",45.11545346),("USD-ETH",2.0),("USD-DGB",1000.0),("InlegEURO",220.42)]
*/

// let ar = line;  //.to_string().iter();

        // let ar = &line;
        let ar = [("USD",45.11545346),("USD-ETH",2.0),("USD-DGB",1000.0),("InlegEURO",220.42)];

        println!("Eerste tuple; eerste item {}", ar[0].0);
        println!("Eerste tuple; tweede item {}", ar[0].1);

        let mut bs = std::collections::BTreeMap::<&str, f64>::new();
        for &(key, value) in ar.iter() {
            bs.insert(key, value);
        }
        println!("BTreeMap:");
        for (key, value) in bs.iter() {
            print!("  {}: {},", key, value);
        }
        // println!("\n    {:?}", hs);
        println!();
        println!("Alle keys:");
        for key in bs.keys() {
            print!("  {}", key);
        }
        println!();
        println!("Sommige keys:");
        println!("  USD:       {:>15}", bs.get("USD").unwrap());
        println!("  USD:(x2)   {:>15}", bs.get("USD").unwrap()*2.);
        println!("  USD-ETH:   {:>15}", bs.get("USD-ETH").unwrap());
        println!("  InlegEuro: {:>15}", bs.get("InlegEURO").unwrap());
    }
}

The problem is that I can print the row from the txt-file, but I cannot use that for filling the BtreeMap. If I put the printed line in ar (literal) it works fine.

So my question is: How do I get a BTreemap from the read line?

For real Rustaceans this should be easy, but for me, a 69 year old dutch python hobbyist starting with rust, its rather difficult.

Thanks in advance for helping me out!
1 Like

Please elaborate. In what specific way can't you do that? Are you getting a compile time error? Or does your code run but fails to produce the expected output? In either case, what exactly happens?

Yes I do. When I comment out the line ar = [("USD",45.11545346), etc and remove the slashes from the line before that I get the following:

Compiling coinrs v0.1.0 (/mnt/Data/RustProjects/coinrs)
error[E0277]: the type String cannot be indexed by {integer}
--> src/main.rs:33:50
|
33 | println!("Eerste tuple; eerste item {}", ar[0].0);
| ^^^^^ String cannot be indexed by {integer}
|
= help: the trait Index<{integer}> is not implemented for String

error[E0277]: the type String cannot be indexed by {integer}
--> src/main.rs:34:50
|
34 | println!("Eerste tuple; tweede item {}", ar[0].1);
| ^^^^^ String cannot be indexed by {integer}
|
= help: the trait Index<{integer}> is not implemented for String

error[E0599]: no method named iter found for reference &&String in the current scope
--> src/main.rs:37:33
|
37 | for &(key, value) in ar.iter() {
| ^^^^ method not found in &&String

Some errors have detailed explanations: E0277, E0599.
For more information about an error, try rustc --explain E0277.
error: could not compile coinrs due to 3 previous errors

And I have tried a lot the last few days. Probably too much.

Well, a line is a String. It's not an array, much less of an array of tuples, so you can't just treat it like that. Does the file have some structure? Are you trying to parse each line into a key-value pair? What is the expected contents of the map after you have read the file?

Iḿ just reading the last line of a simple txt-file (the same file I use for python). No special stucture. Indeed I'm trying to parse it into a key-value pair and be able to get the value by key with i.e. bs.get("USD").unwrap()) and do some calculations.

The result (in python is now):
20220223 22:30:58 Inleg Euro: 220.42
USD/EURO koers: 0.88454616 Inleg USD : 249.19

Naam Koers USD/BTC Aantal $$ €€

USD 1.00000 45.11545346 45.12 39.91
USD-DGB 0.01986 1000.00 19.86 17.57
USD-ETH 2633.43600 2.00000000 5266.87 4658.79
---------------------
Totalen 5331.85 4716.27
Winst/Verlies 2039.67 % 4495.85
--------------------------------------=====================
and that what I want to make in rust.

Then you probably want to use str::split() to obtain the space-separated fields of each line.

And then iterate over the splits? Can you give an example?

Yes. You seem to be trying to get the first and third fields, so you could just ask repeatedly for the next item of the iterator returned by split(), like this.

Thanks a lot. I will try it tomorrow!

Sorry, but I don't have the solution yet. I have:
let lines = [
("USD",45.11545346),("USD-ETH",2.0),("USD-DGB",1000.0),("InlegEURO",220.42)
];
When I remove the "()" and the "fields.next()," and put the values into "" it works almost. I get the following:
thread 'main' panicked at 'called Option::unwrap() on a None value', src/main.rs:16:67
note: run with RUST_BACKTRACE=1 environment variable to display a backtrace.
Line 16 is: let (key, value) = (fields.next().unwrap(), fields.next().unwrap());
I thought it would just stop when there are no more key value pairs in the given string.

Sorry, I have no idea what you are talking about. My demonstrative code example linked above works. It tries to show you how to split up a line once you have some lines. Those lines are supposed to be strings, which your mock data isn't (that's the whole point).

If you have a runtime error to debug in your own code, please post actual code, not a diff described in words (and nothing to diff against).

Sorry, here it is

use std::collections::BTreeMap;

fn main() {
    let lines = [
    // "USD",45.11545346,"USD-ETH",2.0,"USD-DGB",1000.0,"InlegEURO",220.42
    "USD","45.11545346","USD-ETH","2.0","USD-DGB","1000.0","InlegEURO","220.42"
    ];
    //     "USD 1.00000 45.11545346 45.12 39.91",
    //     "USD-DGB 0.01986 1000.00 19.86 17.57",
    //     "USD-ETH 2633.43600 2.00000000 5266.87 4658.79",
    // ];
    let mut map = BTreeMap::new();

    for line in lines {
        let mut fields = line.split(',');
        let (key, value) = (fields.next().unwrap(), fields.next().unwrap());
        let value = value.parse::<f64>().unwrap();
        map.insert(key, value);
    }

    println!("{:#?}", map);
}

You are trying to split on a comma, but your individual lines don't contain commas.

The red line (just one line) is used! ```
"USD","45.11545346","USD-ETH","2.0","USD-DGB","1000.0","InlegEURO","220.42"
Commas all over!

The commas are not part of the strings. Did you want this?

let lines = [
    "USD,45.11545346","USD-ETH,2.0","USD-DGB,1000.0","InlegEURO,220.42"
];
1 Like

YES! Thanks again! I knew I had to learn a lot, and I am learning from you. Thanks again.

And now the next problem:
I have the red string (of strings) in a txt file. I'm trying to read it from that file and put it in the var 'lines' and use in for filling a BTreemap. And that's my problem now. Have been very busy reading, but no solution yet.
Here is my main.rs:

// use std::io::*;
// use std::str::FromStr;
use std::fs::File;
use rev_lines::RevLines;
use std::io::BufReader;
use std::collections::BTreeMap;

fn main() {
       // Haal de laatste regel uit invoer bestand
    let invoer = File::open("/mnt/Data/Coins/Bittrex_invoer_rs.txt").unwrap();
    let rev_lines = RevLines::new(BufReader::new(invoer)).unwrap();
    let n_last_lines = 1;   // We want to display the last line (5 = the last 5 lines)

    let mut lines: Vec<String> = Vec::new();
    let mut counter = 0;
    for line in rev_lines {
        if counter >= n_last_lines {
            break;
        }
        counter = counter + 1;
        lines.push(line);
        for line in lines.iter().rev() {
            // line = line.split(" ");
            println!("Row 23: {}", line);
            // println!("Line split: {:?}", line.to_string().split(" "));
            // let line = &line.split(",");
            println!("\nEerste element in array lines : {:?}", lines[0]);
            println!("Laatste element in array lines : {:?}", lines[lines.len()-1]);
            // let mut fields = lines.split(',');
            // println!("Fields: {:?}", fields);
        }
    }

    let lines = [
    "USD,45.11545346","USD-ETH,2.0","USD-DGB,1000.0","InlegEURO,220.42"
    ];
    // See:https://www.educative.io/courses/learn-rust-from-scratch/N8JjPkwrK8v
    println!("\nHardcoded array:");
    println!("Eerste element in array lines : {:?}", lines[0]);
    println!("Laatste element in array lines : {:?}", lines[lines.len()-1]);
    let mut bm = BTreeMap::new();

    for line in lines {
        let mut fields = line.split(',');
        let (key, value) = (fields.next().unwrap(), fields.next().unwrap());
        let value = value.parse::<f64>().unwrap();
        bm.insert(key, value);
    }

    println!("{:#?}", bm);
    println!();
    println!("Sommige keys:");
    println!("  USD:       {:>15}", bm.get("USD").unwrap());
    println!("  USD:(x2)   {:>15}", bm.get("USD").unwrap()*2.);
    println!("  USD-DGB:   {:>15}", bm.get("USD-DGB").unwrap());
    println!("  InlegEuro: {:>15}", bm.get("InlegEURO").unwrap());
}

In cargo.toml:
[dependencies]
rev_lines = "0.2.1"

Thanks in advance for helping a newbie!
Bauke

Try doing this:

bm.insert(key.to_string(), value);

This is the output:

Row 23: "USD,45.11545346" "USD-ETH,2.0" "USD-DGB,1000.0" "InlegEURO,220.42"

Eerste element in array lines : "\"USD,45.11545346\" \"USD-ETH,2.0\" \"USD-DGB,1000.0\" \"InlegEURO,220.42\""
Laatste element in array lines : "\"USD,45.11545346\" \"USD-ETH,2.0\" \"USD-DGB,1000.0\" \"InlegEURO,220.42\""

Hardcoded array:
Eerste element in array lines : "USD,45.11545346"
Laatste element in array lines : "InlegEURO,220.42"
{
    "InlegEURO": 220.42,
    "USD": 45.11545346,
    "USD-DGB": 1000.0,
    "USD-ETH": 2.0,
}

Sommige keys:
  USD:           45.11545346
  USD:(x2)       90.23090692
  USD-DGB:              1000
  InlegEuro:          220.42

Row 23 is a print from the read line in the txt file. Then Iḿ trying to get the first an d last array elem. Doesn't work (get everything).
After that i use the hardcoded string and with that everything works as you can see in the output above.
Bauke