vortex_array/arrays/primitive/
top_value.rs

1use std::hash::Hash;
2
3use rustc_hash::FxBuildHasher;
4use vortex_dtype::{NativePType, match_each_native_ptype};
5use vortex_error::{VortexExpect, VortexResult};
6use vortex_mask::{AllOr, Mask};
7use vortex_scalar::PValue;
8
9use crate::Array;
10use crate::aliases::hash_map::HashMap;
11use crate::arrays::{NativeValue, PrimitiveArray};
12use crate::variants::PrimitiveArrayTrait;
13
14impl PrimitiveArray {
15    /// Compute most common present value of this array
16    pub fn top_value(&self) -> VortexResult<Option<(PValue, usize)>> {
17        if self.is_empty() {
18            return Ok(None);
19        }
20
21        if self.all_invalid()? {
22            return Ok(None);
23        }
24
25        match_each_native_ptype!(self.ptype(), |$P| {
26            let (top, count) = typed_top_value(self.as_slice::<$P>(), self.validity_mask()?);
27            Ok(Some((top.into(), count)))
28        })
29    }
30}
31
32fn typed_top_value<T>(values: &[T], mask: Mask) -> (T, usize)
33where
34    T: NativePType,
35    NativeValue<T>: Eq + Hash,
36{
37    let mut distinct_values: HashMap<NativeValue<T>, usize, FxBuildHasher> =
38        HashMap::with_hasher(FxBuildHasher);
39    match mask.indices() {
40        AllOr::All => {
41            for value in values.iter().copied() {
42                *distinct_values.entry(NativeValue(value)).or_insert(0) += 1;
43            }
44        }
45        AllOr::None => unreachable!("All invalid arrays should be handled earlier"),
46        AllOr::Some(idxs) => {
47            for &i in idxs {
48                *distinct_values
49                    .entry(NativeValue(unsafe { *values.get_unchecked(i) }))
50                    .or_insert(0) += 1
51            }
52        }
53    }
54
55    let (&top_value, &top_count) = distinct_values
56        .iter()
57        .max_by_key(|&(_, &count)| count)
58        .vortex_expect("non-empty");
59    (top_value.0, top_count)
60}