How can I store a data of varied length into an array or a vector?

Although this may seem like a question posed somewhere else, I couldn't find an appropriate answer to my question. So I am asking here for help!

Problem: I want to throw my data into either a multidimensional array or a vector. The problem is that it has different length for each line. The data (in txt file) I have is element output from gmsh. I am trying to build a finite element method solver. It looks like this:

1 15 2 1 1 1 (6 numbers)
2 15 2 1 2 2
3 1 2 99 1 1 5 (7 numbers)
4 1 2 99 1 5 6
...
...
842 2 2 100 6 170 413 337 (8 numbers)
843 2 2 100 6 146 413 343
844 2 2 100 6 155 396 377

The data is organized in the following manner.
[index] [type] [tag1] [tag2] [tag3] [node1] ... [nodeN]

As you can see from the data, index, type, tag1, tag2, tag3 are common in all lines whereas the number of node data varies depending on the type. For example, type 15 has 1 node, type 1 has 2 nodes, type 2 has 3 nodes.

My initial attempt was to put each line in an object and then put them in a vector using push_back().

I did so because the data will be different from problems to problems, but it was not a good way to handle what I have. As long as I can organize the data, array or vector doesn't matter to me.

Can someone please help me?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#include <iostream>
#include <fstream>
#include <vector>
using namespace std;

typedef struct{
    int eNum;
    int type;
    int tag1;
    int tag2;
    int tag3;
    int nodei;
    int nodej;
    int nodek;
}Elem;

istream& elemVec(istream& in, vector<Elem>& vec) {
    if(in){
		vec.clear();
		Elem e;
		while (in >> e.eNum >> e.type >> e.tag1 >> e.tag2 >> e.tag3 >> e.nodei >> e.nodej >> e.nodek){
			vec.push_back(e);
		}
		in.clear();
    }
    return in;
}
Last edited on
So the amount of nodes aren't fixed and there is no maximum? I suggest changing your struct to:

1
2
3
4
5
6
7
8
typedef struct{
    int eNum;
    int type;
    int tag1;
    int tag2;
    int tag3;
    vector<int> nodes;
}Elem;


And in your function, you will store the data in a vector of them, vector<Elem> elements;.

I also suggest you look into getline and stringstreams for your input operations.

http://en.cppreference.com/w/cpp/string/basic_string/getline
http://en.cppreference.com/w/cpp/io/basic_istringstream
Thank you fg109!!

I took your advice and wrote it like below. It works very well. A minor problem is that some random numbers seem to be stored in the element.nodes vector when the element length is shorter.

For example, for the stringstream that stores
1 15 2 1 1 1 (6 numbers)

integers stored turns out to be
1 15 2 1 1 1 11 969833612 ..... I don't see the end of the vectors of random numbers
Also, they seem to vary every time I run them. I am suspecting that's a problem associated with while(!stream.eof())

I can use it as it is since I know the number of nodes given the type number, but I am worried about memory issues because my computation will get much bigger later on.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
#include <iostream>
#include <fstream>
#include <vector>
#include <string>
#include <sstream>
using namespace std;

typedef struct{
    int eNum;
    int type;
    int tag1;
    int tag2;
    int tag3;
    vector<int> nodes;
}Elem;

int main()
{
    ifstream in("element.txt");
    stringstream buffer;
    buffer << in.rdbuf();
    istringstream contents(buffer.str());
    string line;
    vector<Elem> vec;

    while(getline(contents, line)){
        Elem e;
        e.nodes.clear();
        int n;
        stringstream stream(line);
        stream >> e.eNum >> e.type >> e.tag1 >> e.tag2 >> e.tag3;
        while(!stream.eof()){
            stream >> n;
            e.nodes.push_back(n);
        }
        vec.push_back(e);
        stream.clear();
    }

//this is just to see what gets stored in the nodes vector 
    for(int i = 0; i < 100; i++){
        cout << vec[0].nodes[i] << endl;
    }
    return 0;
}
Last edited on
Well, you know when the EOF bit is set right? It's when you try to read something but there's no longer anything to be read.

Example:

You have a file with 1 line. You use getline(inStream, str) inside a loop to read the file. The loop runs through once and reads a line. A line is read just fine, so EOF is not set. The loop runs again, there nothing to be read so it stores some random junk inside str, and sets the EOF bit. That's why I don't like using the EOF as a loop condition.

Try changing

1
2
3
4
        while(!stream.eof()){
            stream >> n;
            e.nodes.push_back(n);
        }

to

1
2
        while(stream >> n)
            e.nodes.push_back(n);


Also, I'm not sure why you need so many stringstreams. But I guess it's fine as long as it works.
Topic archived. No new replies allowed.