【问题标题】:Thrust: Removing duplicates in key-value arrays推力:删除键值数组中的重复项
【发布时间】:2011-07-28 02:59:32
【问题描述】:

我有一对大小相等的数组,我称它们为键和值。

例如:

K: V
1: 99
1: 100
1: 100
1: 100
1: 103
2: 103
2: 105
3: 45
3: 67

对键进行排序,与每个键相关联的值是 排序。如何删除与每个键关联的值重复 及其对应的密钥?

也就是说,我想将上面的内容压缩为:

1: 99
1: 100
1: 103
2: 103 <-- This should remain, since key is different
2: 105
3: 45
3: 67

我查看了 Thrust 中提供的 stream compaction 功能,但是 找不到任何可以做到这一点的东西。这可能与 推力?还是我需要编写自己的内核来标记重复项 模板,然后将其移除?

【问题讨论】:

    标签: cuda thrust stream-compaction


    【解决方案1】:

    键被排序,与每个键关联的值也被排序。因此,我们可以认为 键值对 已排序。如果thrust::unique 可以将这两个向量视为单个向量,它将直接在此工作。这可以通过使用 zip_iterator 将每个位置的 2 个项目(键值)压缩到单个元组中来实现。

    以下是如何就地实现这一点,并将键值向量修剪为仅唯一元素:

    typedef thrust::device_vector< int >                IntVector;
    typedef IntVector::iterator                         IntIterator;
    typedef thrust::tuple< IntIterator, IntIterator >   IntIteratorTuple;
    typedef thrust::zip_iterator< IntIteratorTuple >    ZipIterator;
    
    IntVector keyVector;
    IntVector valVector;
    
    ZipIterator newEnd = thrust::unique( thrust::make_zip_iterator( thrust::make_tuple( keyVector.begin(), valVector.begin() ) ),
                                         thrust::make_zip_iterator( thrust::make_tuple( keyVector.end(), valVector.end() ) ) );
    
    IntIteratorTuple endTuple = newEnd.get_iterator_tuple();
    
    keyVector.erase( thrust::get<0>( endTuple ), keyVector.end() );
    valVector.erase( thrust::get<1>( endTuple ), valVector.end() );
    

    如果您想压缩并生成一个单独的结果流,您需要为您的类型编写自己的二进制谓词,该谓词会查看元组的两个元素。 thrust::zip_iterator 可用于从单独的数组中形成一个虚拟元组迭代器。

    一个完整的工作示例,您可以这样做:

    #include <iostream>
    #include <thrust/tuple.h>
    #include <thrust/functional.h>
    #include <thrust/device_vector.h>
    #include <thrust/iterator/zip_iterator.h>
    #include <thrust/unique.h>
    
    // Binary predicate for a tuple pair
    typedef thrust::tuple<int, int> tuple_t;
    struct tupleEqual
    {
      __host__ __device__
        bool operator()(tuple_t x, tuple_t y)
        {
          return ( (x.get<0>()== y.get<0>()) && (x.get<1>() == y.get<1>()) );
        }
    };
    
    typedef thrust::device_vector<int>::iterator  intIterator;
    typedef thrust::tuple<intIterator, intIterator> intIteratorTuple;
    typedef thrust::zip_iterator<intIteratorTuple> zipIterator;
    typedef thrust::device_vector<tuple_t>::iterator tupleIterator;
    
    int main(void)
    {
      thrust::device_vector<int> k(9), v(9);
      thrust::device_vector<tuple_t> kvcopy(9);
    
      k[0] = 1; k[1] = 1; k[2] = 1; 
      k[3] = 1; k[4] = 1; k[5] = 2;
      k[6] = 2; k[7] = 3; k[8] = 3;
    
      v[0] = 99;  v[1] = 100; v[2] = 100;
      v[3] = 100; v[4] = 103; v[5] = 103;
      v[6] = 105; v[7] = 45;  v[8] = 67;
    
      zipIterator kvBegin(thrust::make_tuple(k.begin(),v.begin()));
      zipIterator kvEnd(thrust::make_tuple(k.end(),v.end()));
      thrust::copy(kvBegin, kvEnd, kvcopy.begin());
    
      tupleIterator kvend = 
            thrust::unique(kvcopy.begin(), kvcopy.end(), tupleEqual());
    
      for(tupleIterator kvi = kvcopy.begin(); kvi != kvend; kvi++) {
        tuple_t r = *kvi;
        std::cout << r.get<0>() << "," << r.get<1>() << std::endl;
      }
    
      return 0;
    }
    

    【讨论】:

    • Talonmies:你能告诉我一个如何编写一个查看两个数组的二元谓词的例子吗?或者给我指一个网上的例子?我是 C++ 模板元编程的新手。
    • 我发布了一个代码 sn-p 但我不确定它是否是最好的解决方案,所以我将它编辑掉了。我会放一些更“推力”的东西,这将更容易与推力::zip_iterator 一起使用。
    • 完成。您能否尝试该代码并报告它是否适合您?
    • Talonmies:谢谢,这行得通。您能否还添加我如何在键和值向量上应用擦除以将它们调整为新的结束迭代器?
    • 输入向量保持不变 - 示例代码在输出副本中返回压缩流。
    【解决方案2】:

    稍作准备即可进行流压缩。您基本上可以为每个键值对启动一个线程,检查前一个键值对是否相等,如果不相等:在与这些对相同大小的单独数组中设置一个标志(int = 1)。所有其他标志保持未设置(int = 0)。然后根据标志数组对键值对进行流式压缩。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-12-12
      • 1970-01-01
      • 2015-05-13
      • 2010-12-25
      相关资源
      最近更新 更多