【问题标题】:How to count unique integers in unordered_set?如何计算 unordered_set 中的唯一整数?
【发布时间】:2015-05-15 21:52:38
【问题描述】:

一个可能看起来微不足道的问题,但我想知道在我将包含重复整数的数组转换为 unordered_set 之后,是否有一种方法可以获取唯一的整数计数。为了清楚起见,我从一些数组开始,变成一个无序集,突然间,unordered_set 只包含唯一的整数,而我只是在 unordered_set 中整数的重复数之后。 这可能吗? (类似于 unordered_set.count(index) ?)

【问题讨论】:

  • 假设我有数组[2, 1, 2, 1, 2],我把它变成一个无序集合。您是在问如何获取集合中的整数个数(即 2),还是试图获取每个整数出现的次数(所以 2 出现的次数为 3)?第一件事很简单,第二件事不是你会使用 unordered_set 的。
  • 嗯,不是所有值都在一组“唯一”中吗?这不是集合的定义要求之一,它只包含每个“键”中的一个吗?您可能想阅读例如this std::unordered_set reference.
  • 嗨,这是第二件事。我可以使用 unordered_map 做第二件事吗?)
  • 您可以使用 unordered_map,这样您就可以计算每个数字出现的次数!
  • 使用unordered_map<key_type,std::size_t>,而不是unordered_set。对于每个键,增加值。瞧!

标签: c++ hashmap unordered-set


【解决方案1】:

一个可能看起来微不足道的问题,但我想知道在我将包含重复整数的数组转换为 unordered_set 之后,是否有一种方法可以获取唯一的整数计数。

如果容器是连续的,就像一个数组,那么我相信你可以在做一些迭代器数学之后使用ptrdiff_t 来计算它们。不过,我不确定非连续容器。

既然你从一个数组开始:

  1. 在阵列上调用unique
  2. unique 返回iter.end()
  3. 使用iter.begin()iter.end() 计算ptrdiff_t count

请记住,步骤 3 中的计算需要针对 sizeof 和元素进行调整。

但是套用 Beta 的话说,有些容器适合这种情况,而另一些则不适合。如果您有一个无序集(或地图或树),那么信息将不会很容易获得。

【讨论】:

  • 但是我该怎么说呢?你有一个示例实现吗?谢谢
  • @Lexka - 我为您添加了更多信息。 “你有一个示例实现吗?” - 我希望你不是想让我为你实现这个:)
  • 您好,实际上,我使用的不是数组而是 unordered_set,所以我认为您的示例不合适
  • @Lexka - 你说你从一个数组开始:"...在我转换一个包含重复整数的数组之后...".
【解决方案2】:

根据你对user2357112问题的回答我会写一个解决方案。 所以,让我们假设我们将使用一个向量而不是 unordered_set,并且我们的向量具有如下值:

{1, 1, 1, 3, 4, 1, 1, 4, 4, 5, 5};

所以,我们想要获得特定值在向量中出现多少次的数字(我认为是不同的向量),对吧?在这种特定情况下,结果将是:1 出现 5 次,3 出现 1 次,4 出现 3 次,5 出现 2 次。

要完成此操作,一种可能的解决方案如下:

  1. 从源向量中获取唯一条目并将它们存储在不同的向量中,因此该向量将包含:1、3、4、5
  2. 遍历整个唯一向量并从源向量中计算这些元素。
  3. 打印结果

第 1 点的代码可以是这样的:

template <typename Type>
vector<Type> unique_entries (vector<Type> vec) { 
    for (auto iter = vec.begin (); iter != vec.end (); ++iter) { 
        auto f = find_if (iter+1, vec.end (), [&] (const Type& val) {
           return *iter == val; 
        });

        if (f != vec.end ()) { 
            vec.erase (remove (iter+1, vec.end (), *iter), vec.end ());
        }
    }
    return vec;
}

第2点的代码可以是这样的:

template <typename Type>
struct Properties { 
    Type key;
    long int count;
};

template <typename Type>
vector<Properties<Type>> get_properties (const vector<Type>& vec) { 
    vector<Properties<Type>> ret {};
    auto unique_vec = unique_entries (vec);
    for (const auto& uv : unique_vec) { 
        auto c = count (vec.begin (), vec.end (), uv); // (X)
        ret.push_back ({uv, c});
    }
    return ret;
}

当然我们不需要Properties 类来存储key 和count 值,你可以只返回一个int 的向量(带有元素的数量),但正如我所说,它是一种可能的解决方案。因此,通过使用 unique_entries 我们得到一个具有唯一条目 (:) 的向量,然后我们可以遍历整个向量 vec (get_properties,使用 std:: count 标记为 (X)),并 push_back 属性对象到向量 ret

第 3 点的代码可以是这样的:

template <typename Type>
void show (const vector<Properties<Type>>& vec) { 
    for (const auto& v : vec) { 
        cout << v.key << " " << v.count << endl;
    }
}

// usage below
vector<int> vec {1, 1, 1, 3, 4, 1, 1, 4, 4, 5, 5};
auto properties = get_properties (vec);
show (properties);

结果如下所示:

1 5
3 1
4 3
5 2

值得注意的是,此示例是使用模板编写的,以提供在向量中选择元素类型的灵活性。如果要存储 long、long long、short 等值,而不是 int 类型,只需更改源向量的定义即可,例如:

vector<unsigned long long> vec2 {1, 3, 2, 3, 4, 4, 4, 4, 3, 3, 2, 3, 1, 7, 2, 2, 2, 1, 6, 5};
show (get_properties (vec2));

将产生:

1 3
3 5
2 5
4 4
7 1
6 1
5 1

这是想要的结果。

还有一点,你也可以用字符串向量来做到这一点。

vector<string> vec_str {"Thomas", "Rick", "Martin", "Martin", "Carol", "Thomas", "Martin", "Josh", "Jacob", "Jacob", "Rick"};
show (get_properties (vec_str));

结果是:

Thomas 2
Rick 2
Martin 3
Carol 1
Josh 1
Jacob 2

【讨论】:

  • 你好,这是一个非常好的和复杂的答案,但我实际上是在使用 unordered_map,因为人们早些时候明确表示使用 unordered_set 是没有用的。你知道如何在不从头开始编写代码的情况下使用 unordered_map 吗?顶多肯定是三线操作吧?
  • 很抱歉,但目前我没有任何其他解决方案,尤其是使用 unordered_map 的解决方案。
【解决方案3】:

我假设您正在尝试获取唯一值列表及其出现次数。如果是这种情况,那么std::map 提供了最干净、最简单的解决方案:

//Always prefer std::vector (or at least std::array) over raw arrays if you can
std::vector<int> myInts {2,2,7,8,3,7,2,3,46,7,2,1}; 

std::map<int, unsigned> uniqueValues;

//Get unique values and their count
for (int val : myInts)
    ++uniqueValues[val];

//Output:
for (const auto & val : uniqueValues)
    std::cout << val.first << " occurs " << val.second << " times." << std::endl;

在这种情况下,它不必是std::unordered_set

【讨论】:

    猜你喜欢
    • 2016-04-30
    • 1970-01-01
    • 1970-01-01
    • 2018-12-18
    • 2018-02-20
    • 1970-01-01
    • 2020-06-10
    • 2018-03-11
    • 2012-09-25
    相关资源
    最近更新 更多