Reputation: 5
I have written a program in c++17 using the boost::filesystem library that takes a path as an argument and returns a map:
map<string, vector<string>>
where each key is a directory (boost::filesystem::path converted to string), and each file in each directory is pushed to the value vector.
First, I create a vector of paths from the path given as an argument:
// Method to create vector of paths
vector<path> InToVecsOne(path p, vector<path> v1)
{
for(auto entry : recursive_directory_iterator(p))
{
if(is_directory(entry))
{
v1.push_back(entry);
}
}
return v1;
}
Then, I create the map using the vector as follows:
// Function takes a vector of paths and returns map of key-value pair path-vector<string>
map<string,vector<string>> FileMap(vector<path> v1,
map<string,vector<string>> m, vector<string> v2)
{
for(auto p : v1)
{
// iterate over each entry in path p
for(auto entry : directory_iterator(p))
{
if(is_regular_file(entry) == true)
{
// add file to vector<string>
v2.push_back(basename(entry) + " ");
}
}
// convert path to pathname (DirX) string
string pathname = basename(p);
m.insert(make_pair(pathname, v2));
v2.erase(v2.begin(), v2.end()); // remove contents after iterating
}
return m;
}
Using my sandbox directory as a test path, I get the following output when printing the contents of my map:
DirA: Z X Y
DirB: Z X Y
DirBB: X Y YY
DirC: Z
DirCC: ZZ X Y YY
As noticeable, the keys are DirA, DirB, DirBB, etc. and the values are Z, X, Y etc.
What I want to do now is to transform things so that my output looks like:
X : DirA, DirB, DirBB, DirCC
Y : DirA, DirB, DirBB, DirCC
etc.
I think the best way for this would be either to: 1. re-write the map method, or 2. iterate over the contents in the map, compare if the value is associated with a key and add this value to a new data structure.
I am not sure of which would be easier, or how the second one would look like, and hence would need some advice.
Thanks.
Extension:
Following comment to create a map of filename-path pairs, I encountered a new problem after creating this new map from the old map above. My function is as follows:
// Make new map where file is key, and dir is value. m1 is old map, m2 is new map
map<string,vector<string>> FinalMap(map<string,vector<string>> m1,
map<string,vector<string>> m2, vector<string> dirnames)
{
// iterate over each key
for(map<string,vector<string>>::const_iterator it = m1.begin(); it != m1.end(); ++it)
{
string dirname = it->first;
dirnames.push_back(dirname);
vector<string> files = it->second;
// iterate over elements in vector<string> files
for(auto i : files)
{
m2.insert(make_pair(i, dirnames));
}
dirnames.erase(dirnames.begin(), dirnames.end());
}
return m2;
}
However, now my output is as follows:
X : DirA
Y : DirA
YY : DirBB
Z : DirA
ZZ : DirCC
I need it to be:
X : DirA, DirB, DirBB
etc. given that the file X is in DirA, DirB and DirBB. Therefore, I have to alter the function FileMap.
Upvotes: 0
Views: 1521
Reputation: 66224
Your attempt in doing as described in comments is incorrect. It should look like this:
std::map<std::string, std::vector<std::string>>
FinalMap(std::map<std::string, std::vector<std::string>>const& folderToFiles)
{
std::map<std::string, std::vector<std::string>> fileToFolders;
for (auto const& pr : folderToFiles)
{
for (auto const& file : pr.second)
fileToFolders[file].push_back(pr.first);
}
return fileToFolders;
}
That's it. This enumerates each mapping of folder-to-filesand creates a new mapping of file-to-folders. I'm pretty sure, was what you were looking for.
Upvotes: 0
Reputation: 62799
You could use a boost::bimap
instead of a std::map, and get both Dir -> File and File -> Dir lookups.
#include <boost/bimap.hpp>
using file_map = boost::bimap<std::string, boost::bimaps::multi_set_of<std::string>>;
You would then insert a pathname, filename
pair, rather than gathering a vector
of filenames to associate with a path.
Note that if you are only using the base name of a directory, you may get duplicates. Store either the whole path, or a multi_set_of
on both sides.
Upvotes: 0