【问题标题】:Update element stl list of lists更新元素 stl 列表列表
【发布时间】:2020-05-14 04:08:43
【问题描述】:

我正在处理整数向量列表 (std::list<std::list<std::vector<int>>> z(nlevel))。

我可能有类似的东西:

{ {1} {2} {3} }
{ {1 2} {2 1} {1 3} }
{ {1 2 3} {2 1 3} {1 2 4} }

我需要删除整数的非唯一组合,例如,上面列表的第二个元素应该变成

{ { 1 2 } {1 3} }

这是一个大对象,所以我试图通过引用更新最外层列表的每个元素。我尝试过类似的方法:

lit = z.begin();
for (i = 0; i < nlevel; i++) {
    distinct_z(*lit, primes);
    lit++;
}

其中distinct_z 是一个通过引用查找唯一向量组合的函数,但这似乎不会影响z 列表。注意:distinct_z 在我已经使用列表的第 i 个元素的代码的另一部分中工作正常。我在下面提供了distinct_z。它包括来自 R 中 Rcpp 包的一些独特数据类型,但希望是可以理解的。本质上,我使用素数的对数和来识别整数的非唯一组合,因为整数的顺序无关紧要。重申一下,distinct_z 确实在我的代码的另一部分工作,我将一个实际的整数向量列表传递给它。问题似乎是我正在尝试使用迭代器传递一些东西。

void distinct_lz(std::list<std::vector<int>> &lz,
                      const IntegerVector &primes) {
  int i, j, npids = lz.size();

  NumericVector pids(npids);
  std::list<std::vector<int>>::iterator lit = lz.begin();
  int z_size = lit -> size();
  for(i = 0; i < npids; i++) {
    for (j = 0; j < z_size; j++) {
      // cprime = primes[lit -> at(j)];
      // pids[i] += log(cprime);
      // cprime = primes[lit -> at(j)];
      pids[i] += log(primes[lit -> at(j)]);
    }
    lit++;
  }
  LogicalVector dup = duplicated(round(pids, 8));
  lit = lz.begin();
  for(i = 0; i < npids; i++) {
    if(dup(i) == 1) {
      lz.erase(lit);
    }
    lit++;
  }
}

什么是做我想做的最好的方法?

背景:数据结构可能看起来不必要地复杂,但我使用广度优先方法从顶点开始枚举所有连接的子图。因此,给定一个当前子图,我看到连接了哪些其他顶点以创建一组新的子图并重复。我最初使用整数向量列表来执行此操作,但删除重复项的速度非常慢,因为如果我删除了部分向量,我必须复制当前对象。即使结构更复杂,这种方法也快得多。

编辑:这是一个主要做我想要的解决方案,尽管它会导致一些不希望的复制。我更新了distinct_z 以返回对象的副本而不是修改引用,然后替换了lit 处的元素。

  lit = z.begin();
  for (i = 0; i < nlevel; i++) {
    (*lit) = distinct_z(*lit, primes);
    lit++;
  }

【问题讨论】:

  • 显示distinct_z 应该会有所帮助...
  • 删除非唯一元素最简单的方法是使用不允许重复元素的容器,例如std::set。更好地展示您的尝试,否则这有可能因为“如何删除重复”问题的重复而被关闭,这可能是一个很好的方向,但当然不能解决代码中的问题。另请阅读minimal reproducible example
  • @Jarod42 @formelyknown 我添加了distinct_z。谢谢你的帮助! distinct_z 在我的代码的其他部分中正常运行,但在尝试使用迭代器时不能在此特定上下文中。
  • 似乎有趣的部分在duplicated 中,您没有显示代码。请阅读minimal reproducible example

标签: c++ list stl iterator


【解决方案1】:

在 C++ 中有一个众所周知的习惯用法,称为 erase-remove idiom,用于从 STL 容器中删除元素。它基本上涉及将不需要的项目洗牌到容器的末端,然后擦除不需要的尾部。

我们可以使用谓词函数(例如 lambda)来选择我们想要擦除的项目并使用来自 &lt;algorithm&gt; 的函数。在您的情况下,我们使用一组整数 (std::&lt;set&lt;int&gt;&gt;) 来存储唯一组合。将列表中的每个向量转换为一组整数,如果以前没有见过,则将其删除。

#include <set>
#include <list>
#include <vector>
#include <algorithm>
#include <iostream>

void distinct_lz(std::list<std::vector<int>>& lz)
{
    std::set<std::set<int>> unqiueNums;

    lz.erase(std::remove_if(lz.begin(), lz.end(),
        [&unqiueNums](std::vector<int>& v) {
            std::set<int> s{ v.cbegin(), v.cend() };
            if (unqiueNums.find(s) != unqiueNums.end())
                return true;
            else
            {
                unqiueNums.insert(s);
                return false;
            }
        }), lz.end());

}

int main()
{
    std::list<std::vector<int>> lv = { {1, 2}, {2, 1}, {1, 3}, {3,4} };
    distinct_lz(lv);
    for (auto &v: lv)
    {
        for( auto n: v)
        {
            std::cout << n << " ";
        }

        std::cout << "\n";
    }
}

输出:

1 2
1 3
3 4

工作版here.

【讨论】:

  • 感谢您的帮助。你真的超越了。
  • @dr_jfrench 没问题。
猜你喜欢
  • 2012-10-15
  • 1970-01-01
  • 2011-08-17
  • 1970-01-01
  • 1970-01-01
  • 2016-01-27
  • 2016-04-02
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多