C++将一个向量附加到另一个向量

发布于 2024-09-10 20:07:29 字数 650 浏览 5 评论 0原文

我完全理解这个问题已经被问了很多次,但我要求的是一种特定的变体,而我的 search-foo 已经放弃了,因为我只找到了将一个现有向量附加到另一个向量的算法,但没有从函数返回。

我有一个列出目录中所有文件的函数:

vector<string> scanDir( const string& dir )

它可以在内部调用自身(对于子目录)。

我需要一种将返回值附加到调用者向量的简短方法。我脑子里有这样的东西(但当然它不存在:( ):

vector<string> fileList;
//...
fileList.append( scanDir(subdirname) );

我担心存储返回值并将其插入 fileList 会带来性能问题。我的意思是:

vector<string> temp( scanDir(subdirname) );
copy( temp.begin(), temp.end(), back_inserter(fileList) );

谢谢!

PS:我'我不强迫自己使用向量,任何其他性能同样出色并且可以防止潜在的大型复制操作的容器对我来说都很好。

I fully understand this question has been asked a lot, but I'm asking for a specific variation and my search-foo has given up, as I've only found algorithms that append one existing vector to another, but not one returned to from a function.

I have this function that lists all files in a directory:

vector<string> scanDir( const string& dir )

which may call itself internally (for subdirectories).

I need a short way of appending the returned value to the caller's vector. I have in my mind something like this (but of course it doesn't exist :( ):

vector<string> fileList;
//...
fileList.append( scanDir(subdirname) );

I fear that storing the return value and inserting it in fileList would bring performance badness. What I mean is this:

vector<string> temp( scanDir(subdirname) );
copy( temp.begin(), temp.end(), back_inserter(fileList) );

Thanks!

PS: I'm not forcing myself to using vector, any other container that performs equally well and can prevent the potential large copy operation is fine by me.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(10

执手闯天涯 2024-09-17 20:07:29

为什么不直接将向量作为参数传递呢?然后每次调用都可以附加到同一个向量,而无需复制。或者创建一个实现类,将元素累积到成员对象中。

Why not just pass the vector as an argument? Then every invocation can append to the same vector, without copying. Or create an implementation class which accumulates the elements into a member object.

街角卖回忆 2024-09-17 20:07:29

如果您可以更改 scanDir,请将其设为接受输出迭代器的(模板)函数:

template <class OutIt>
void scanDir(const std::string& dirname, OutIt it) {
  // ...
  // Scan subdir
  scanDir(subdir, it);
  // ...
}

您将获得额外的好处,能够填充各种数据结构,例如

std::vector<string> vector;
scanDir(dir1, std::back_inserter(vector));
std::set<string> fileset
scanDir(dir1, std::inserter(fileset, fileset.begin()));

等。

编辑(请参阅注释...)

要使用此函数进行类成员初始化,您可以在构造函数中调用它,

class MyClass {
private:
  std::vector<string> m_fileList;
public:
  MyClass(const std::string& dirname) {
    scanDir(dirname, std::back_inserter(m_fileList);
  }
}

或者使用包装函数,

std::vector<string> scanDir(const std::string& dirname) {
  std::vector<string> result;
  scanDir(dirname, std::back_inserter(result);
  return result;
}

class MyClass {
// Same as above..
  MyClass(const std::string& dirname) : m_fileList(scanDir(dirname)) { }
}

出于性能考虑,我更喜欢第一个版本(以及其他版本) ) 原因...

If you're in the position to change scanDir, make it a (template) function accepting an output iterator:

template <class OutIt>
void scanDir(const std::string& dirname, OutIt it) {
  // ...
  // Scan subdir
  scanDir(subdir, it);
  // ...
}

You'll have the additional benefit to be able to fill all sort of data structures like

std::vector<string> vector;
scanDir(dir1, std::back_inserter(vector));
std::set<string> fileset
scanDir(dir1, std::inserter(fileset, fileset.begin()));

etc.

EDIT (see comment ...)

For using this function for class member initialization, you could either call it in the constructor as in

class MyClass {
private:
  std::vector<string> m_fileList;
public:
  MyClass(const std::string& dirname) {
    scanDir(dirname, std::back_inserter(m_fileList);
  }
}

or using a wrapper function

std::vector<string> scanDir(const std::string& dirname) {
  std::vector<string> result;
  scanDir(dirname, std::back_inserter(result);
  return result;
}

class MyClass {
// Same as above..
  MyClass(const std::string& dirname) : m_fileList(scanDir(dirname)) { }
}

I would prefer the first version for performance (and other) reasons ...

十级心震 2024-09-17 20:07:29

PS:我不会强迫自己使用向量,任何其他性能同样出色并且可以防止潜在的大型复制操作的容器对我来说都很好。

好吧,如果您使用 list 并调用 a.splice(a.end(), b); 您将完全避免复制操作。 list 通常是一个链表,而不是像 vector 那样的数组,因此这对性能和使用有很大影响。但是 splice 的运行时间复杂度为 O(1),所以这是一个很好的好处。

PS: I'm not forcing myself to using vector, any other container that performs equally well and can prevent the potential large copy operation is fine by me.

Well, if you use a list and call a.splice(a.end(), b); you'll avoid the copy operation completely. A list is generally going to be a linked list rather than an array as is the case with a vector, so this has a lot of performance and usage implications. But splice runs in O(1), so that's a nice benefit.

情魔剑神 2024-09-17 20:07:29
vector<string> fileList;
vector<string> temp( scanDir(subdirname) );

fileList.insert(fileList.end(), temp.begin(), temp.end());

我希望这对你有帮助。

vector<string> fileList;
vector<string> temp( scanDir(subdirname) );

fileList.insert(fileList.end(), temp.begin(), temp.end());

I hope that helped you.

幻想少年梦 2024-09-17 20:07:29

使用 std::list 并使用 std::list::splice 追加。

来自拼接文档

该操作不涉及任何元素对象的构造或销毁,并且除了第三个版本之外,它是在恒定时间内执行的。

Use std::list and append by using std::list::splice.

From the docs for splice:

The operation does not involve the construction or destruction of any element object and, except for the third version, it is performed in constant time.

喵星人汪星人 2024-09-17 20:07:29

相反,

vector<string> temp( scanDir(subdirname) );

您可以执行

vector<string> const& temp = scanDir(subdirname);

并继续复制:

fileList.insert(fileList.end(), temp.begin(), temp.end());

Instead of

vector<string> temp( scanDir(subdirname) );

you can do

vector<string> const& temp = scanDir(subdirname);

and proceed with the copy:

fileList.insert(fileList.end(), temp.begin(), temp.end());
命硬 2024-09-17 20:07:29

递归函数必须多次复制所有内容,准确地说是 O(深度)(即:叶级别中的所有内容都将被一次又一次复制,直到到达根)。

最好的方法是将其分成两个不同的函数:

vector<string> scanDir(string path)
{
  vector<string> retval;

  scanDir(path, &retval);

  return retval;
}

static void scanDir(string path, vector<string>& output)
{
  .. scan
  .. append to output 
}

The recursive function will have to copy everything multiple times, O(depth) to be precise (i.e: everything in the leaf level will be copied again and again until it reaches the root).

The best method would be splitting this into two different functions:

vector<string> scanDir(string path)
{
  vector<string> retval;

  scanDir(path, &retval);

  return retval;
}

static void scanDir(string path, vector<string>& output)
{
  .. scan
  .. append to output 
}
再见回来 2024-09-17 20:07:29

辅助功能怎么样?

template<class T>
std::vector<T>& VectorAppend(std::vector<T> &target, const std::vector<T> &source)
{
    size_t insertPos = target.size();
    target.resize(target.size() + source.size());
    std::copy(source.begin(), source.end(), target.begin() + insertPos);
    return target;
}

How about a helper function?

template<class T>
std::vector<T>& VectorAppend(std::vector<T> &target, const std::vector<T> &source)
{
    size_t insertPos = target.size();
    target.resize(target.size() + source.size());
    std::copy(source.begin(), source.end(), target.begin() + insertPos);
    return target;
}
超可爱的懒熊 2024-09-17 20:07:29

这可能不是最简单的解决方案,但是做一些相当于 C# 的 StringBuilder 的事情怎么样?

创建一个列表<向量<字符串> > 然后您可以将从调用 scanDir() 中获得的所有向量附加到列表中。

如果您绝对必须在最后有一个向量,那么一旦创建一个新向量,您就可以将其分配得足够大,以便不需要调整大小,然后组装您的成品。

或者,您可以创建一个新类(如果需要,从向量派生)并在内部使用列表<向量。 >来存储元素。然后,您只需让迭代器迭代第一个列表中的元素,然后当它到达末尾时,转到下一个列表中的元素,仅在到达最后一个列表的末尾时返回 container::end 。

This might not be the simplest possible solution, but what about doing something equivalent to C#'s StringBuilder?

Make a list<vector<string> > then you can append all of the vectors that you get from your calls to scanDir() to the list.

If you absolutely have to have a single vector at the end, you can then, once make a new vector, allocate it large enough so that it won't need to resize, and assemble your finished product.

Alternatively, you could make a new class (if needed that derives from vector<T>) and internally uses the list<vector<T> > to store the elements. Then you would just make your iterators iterate through the elements in the first list, then when it reaches the end go for the elements in the next list, only returning container::end when you reached the end of the last list.

淑女气质 2024-09-17 20:07:29

我知道这并不能直接回答您的问题,但就您的根本目标而言,您可能只想简单地根据 boost::filesystem 重新实现您的函数。目录迭代器已经是递归的,因此您不需要自己进行递归调用。您可以简单地在迭代器上的循环中填充列表。有一个 ls 的示例实现:
http://www.boost.org/doc/ libs/1_43_0/libs/filesystem/example/simple_ls.cpp

您还可以获得(理论上的)平台独立性、相对广泛的采用(采用更多的情况下可以更快地发现错误)等额外好处

I know this doesn't answer your question directly, but with regard to your underlying goal, you might want to simply reimplement your function in terms of boost::filesystem. The directory iterator is already recursive so you don't need to make recursive calls of your own. You could simply populate a list in a loop over the iterator. There is an example implementation of ls:
http://www.boost.org/doc/libs/1_43_0/libs/filesystem/example/simple_ls.cpp

You also get the added benefit of (theoretical) platform independence, relatively wide adoption (bugs get ferreted out more quickly with more adoption), etc

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文