use crate::builder::{PrimitiveDictionaryBuilder, StringDictionaryBuilder};
use crate::cast::AsArray;
use crate::iterator::ArrayIter;
use crate::types::*;
use crate::{
make_array, Array, ArrayAccessor, ArrayRef, ArrowNativeTypeOp, PrimitiveArray, Scalar,
StringArray,
};
use arrow_buffer::bit_util::set_bit;
use arrow_buffer::buffer::NullBuffer;
use arrow_buffer::{ArrowNativeType, BooleanBuffer, BooleanBufferBuilder};
use arrow_data::ArrayData;
use arrow_schema::{ArrowError, DataType};
use std::any::Any;
use std::sync::Arc;
pub type Int8DictionaryArray = DictionaryArray<Int8Type>;
pub type Int16DictionaryArray = DictionaryArray<Int16Type>;
pub type Int32DictionaryArray = DictionaryArray<Int32Type>;
pub type Int64DictionaryArray = DictionaryArray<Int64Type>;
pub type UInt8DictionaryArray = DictionaryArray<UInt8Type>;
pub type UInt16DictionaryArray = DictionaryArray<UInt16Type>;
pub type UInt32DictionaryArray = DictionaryArray<UInt32Type>;
pub type UInt64DictionaryArray = DictionaryArray<UInt64Type>;
pub struct DictionaryArray<K: ArrowDictionaryKeyType> {
data_type: DataType,
keys: PrimitiveArray<K>,
values: ArrayRef,
is_ordered: bool,
}
impl<K: ArrowDictionaryKeyType> Clone for DictionaryArray<K> {
fn clone(&self) -> Self {
Self {
data_type: self.data_type.clone(),
keys: self.keys.clone(),
values: self.values.clone(),
is_ordered: self.is_ordered,
}
}
}
impl<K: ArrowDictionaryKeyType> DictionaryArray<K> {
pub fn new(keys: PrimitiveArray<K>, values: ArrayRef) -> Self {
Self::try_new(keys, values).unwrap()
}
pub fn try_new(keys: PrimitiveArray<K>, values: ArrayRef) -> Result<Self, ArrowError> {
let data_type = DataType::Dictionary(
Box::new(keys.data_type().clone()),
Box::new(values.data_type().clone()),
);
let zero = K::Native::usize_as(0);
let values_len = values.len();
if let Some((idx, v)) =
keys.values().iter().enumerate().find(|(idx, v)| {
(v.is_lt(zero) || v.as_usize() >= values_len) && keys.is_valid(*idx)
})
{
return Err(ArrowError::InvalidArgumentError(format!(
"Invalid dictionary key {v:?} at index {idx}, expected 0 <= key < {values_len}",
)));
}
Ok(Self {
data_type,
keys,
values,
is_ordered: false,
})
}
pub fn new_scalar<T: Array + 'static>(value: Scalar<T>) -> Scalar<Self> {
Scalar::new(Self::new(
PrimitiveArray::new(vec![K::Native::usize_as(0)].into(), None),
Arc::new(value.into_inner()),
))
}
pub unsafe fn new_unchecked(keys: PrimitiveArray<K>, values: ArrayRef) -> Self {
let data_type = DataType::Dictionary(
Box::new(keys.data_type().clone()),
Box::new(values.data_type().clone()),
);
Self {
data_type,
keys,
values,
is_ordered: false,
}
}
pub fn into_parts(self) -> (PrimitiveArray<K>, ArrayRef) {
(self.keys, self.values)
}
pub fn keys(&self) -> &PrimitiveArray<K> {
&self.keys
}
pub fn lookup_key(&self, value: &str) -> Option<K::Native> {
let rd_buf: &StringArray = self.values.as_any().downcast_ref::<StringArray>().unwrap();
(0..rd_buf.len())
.position(|i| rd_buf.value(i) == value)
.and_then(K::Native::from_usize)
}
pub fn values(&self) -> &ArrayRef {
&self.values
}
pub fn value_type(&self) -> DataType {
self.values.data_type().clone()
}
pub fn len(&self) -> usize {
self.keys.len()
}
pub fn is_empty(&self) -> bool {
self.keys.is_empty()
}
pub fn is_ordered(&self) -> bool {
self.is_ordered
}
pub fn keys_iter(&self) -> impl Iterator<Item = Option<usize>> + '_ {
self.keys.iter().map(|key| key.map(|k| k.as_usize()))
}
pub fn key(&self, i: usize) -> Option<usize> {
self.keys.is_valid(i).then(|| self.keys.value(i).as_usize())
}
pub fn slice(&self, offset: usize, length: usize) -> Self {
Self {
data_type: self.data_type.clone(),
keys: self.keys.slice(offset, length),
values: self.values.clone(),
is_ordered: self.is_ordered,
}
}
pub fn downcast_dict<V: 'static>(&self) -> Option<TypedDictionaryArray<'_, K, V>> {
let values = self.values.as_any().downcast_ref()?;
Some(TypedDictionaryArray {
dictionary: self,
values,
})
}
pub fn with_values(&self, values: ArrayRef) -> Self {
assert!(values.len() >= self.values.len());
let data_type =
DataType::Dictionary(Box::new(K::DATA_TYPE), Box::new(values.data_type().clone()));
Self {
data_type,
keys: self.keys.clone(),
values,
is_ordered: false,
}
}
pub fn into_primitive_dict_builder<V>(self) -> Result<PrimitiveDictionaryBuilder<K, V>, Self>
where
V: ArrowPrimitiveType,
{
if !self.value_type().is_primitive() {
return Err(self);
}
let key_array = self.keys().clone();
let value_array = self.values().as_primitive::<V>().clone();
drop(self.keys);
drop(self.values);
let key_builder = key_array.into_builder();
let value_builder = value_array.into_builder();
match (key_builder, value_builder) {
(Ok(key_builder), Ok(value_builder)) => Ok(unsafe {
PrimitiveDictionaryBuilder::new_from_builders(key_builder, value_builder)
}),
(Err(key_array), Ok(mut value_builder)) => {
Err(Self::try_new(key_array, Arc::new(value_builder.finish())).unwrap())
}
(Ok(mut key_builder), Err(value_array)) => {
Err(Self::try_new(key_builder.finish(), Arc::new(value_array)).unwrap())
}
(Err(key_array), Err(value_array)) => {
Err(Self::try_new(key_array, Arc::new(value_array)).unwrap())
}
}
}
pub fn unary_mut<F, V>(self, op: F) -> Result<DictionaryArray<K>, DictionaryArray<K>>
where
V: ArrowPrimitiveType,
F: Fn(V::Native) -> V::Native,
{
let mut builder: PrimitiveDictionaryBuilder<K, V> = self.into_primitive_dict_builder()?;
builder
.values_slice_mut()
.iter_mut()
.for_each(|v| *v = op(*v));
Ok(builder.finish())
}
pub fn occupancy(&self) -> BooleanBuffer {
let len = self.values.len();
let mut builder = BooleanBufferBuilder::new(len);
builder.resize(len);
let slice = builder.as_slice_mut();
match self.keys.nulls().filter(|n| n.null_count() > 0) {
Some(n) => {
let v = self.keys.values();
n.valid_indices()
.for_each(|idx| set_bit(slice, v[idx].as_usize()))
}
None => {
let v = self.keys.values();
v.iter().for_each(|v| set_bit(slice, v.as_usize()))
}
}
builder.finish()
}
}
impl<T: ArrowDictionaryKeyType> From<ArrayData> for DictionaryArray<T> {
fn from(data: ArrayData) -> Self {
assert_eq!(
data.buffers().len(),
1,
"DictionaryArray data should contain a single buffer only (keys)."
);
assert_eq!(
data.child_data().len(),
1,
"DictionaryArray should contain a single child array (values)."
);
if let DataType::Dictionary(key_data_type, _) = data.data_type() {
assert_eq!(
&T::DATA_TYPE,
key_data_type.as_ref(),
"DictionaryArray's data type must match, expected {} got {}",
T::DATA_TYPE,
key_data_type
);
let values = make_array(data.child_data()[0].clone());
let data_type = data.data_type().clone();
let keys = PrimitiveArray::<T>::from(unsafe {
data.into_builder()
.data_type(T::DATA_TYPE)
.child_data(vec![])
.build_unchecked()
});
Self {
data_type,
keys,
values,
is_ordered: false,
}
} else {
panic!("DictionaryArray must have Dictionary data type.")
}
}
}
impl<T: ArrowDictionaryKeyType> From<DictionaryArray<T>> for ArrayData {
fn from(array: DictionaryArray<T>) -> Self {
let builder = array
.keys
.into_data()
.into_builder()
.data_type(array.data_type)
.child_data(vec![array.values.to_data()]);
unsafe { builder.build_unchecked() }
}
}
impl<'a, T: ArrowDictionaryKeyType> FromIterator<Option<&'a str>> for DictionaryArray<T> {
fn from_iter<I: IntoIterator<Item = Option<&'a str>>>(iter: I) -> Self {
let it = iter.into_iter();
let (lower, _) = it.size_hint();
let mut builder = StringDictionaryBuilder::with_capacity(lower, 256, 1024);
builder.extend(it);
builder.finish()
}
}
impl<'a, T: ArrowDictionaryKeyType> FromIterator<&'a str> for DictionaryArray<T> {
fn from_iter<I: IntoIterator<Item = &'a str>>(iter: I) -> Self {
let it = iter.into_iter();
let (lower, _) = it.size_hint();
let mut builder = StringDictionaryBuilder::with_capacity(lower, 256, 1024);
it.for_each(|i| {
builder
.append(i)
.expect("Unable to append a value to a dictionary array.");
});
builder.finish()
}
}
impl<T: ArrowDictionaryKeyType> Array for DictionaryArray<T> {
fn as_any(&self) -> &dyn Any {
self
}
fn to_data(&self) -> ArrayData {
self.clone().into()
}
fn into_data(self) -> ArrayData {
self.into()
}
fn data_type(&self) -> &DataType {
&self.data_type
}
fn slice(&self, offset: usize, length: usize) -> ArrayRef {
Arc::new(self.slice(offset, length))
}
fn len(&self) -> usize {
self.keys.len()
}
fn is_empty(&self) -> bool {
self.keys.is_empty()
}
fn offset(&self) -> usize {
self.keys.offset()
}
fn nulls(&self) -> Option<&NullBuffer> {
self.keys.nulls()
}
fn logical_nulls(&self) -> Option<NullBuffer> {
match self.values.nulls() {
None => self.nulls().cloned(),
Some(value_nulls) => {
let mut builder = BooleanBufferBuilder::new(self.len());
match self.keys.nulls() {
Some(n) => builder.append_buffer(n.inner()),
None => builder.append_n(self.len(), true),
}
for (idx, k) in self.keys.values().iter().enumerate() {
let k = k.as_usize();
if k < value_nulls.len() && value_nulls.is_null(k) {
builder.set_bit(idx, false);
}
}
Some(builder.finish().into())
}
}
}
fn is_nullable(&self) -> bool {
!self.is_empty() && (self.nulls().is_some() || self.values.is_nullable())
}
fn get_buffer_memory_size(&self) -> usize {
self.keys.get_buffer_memory_size() + self.values.get_buffer_memory_size()
}
fn get_array_memory_size(&self) -> usize {
std::mem::size_of::<Self>()
+ self.keys.get_buffer_memory_size()
+ self.values.get_array_memory_size()
}
}
impl<T: ArrowDictionaryKeyType> std::fmt::Debug for DictionaryArray<T> {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
writeln!(
f,
"DictionaryArray {{keys: {:?} values: {:?}}}",
self.keys, self.values
)
}
}
pub struct TypedDictionaryArray<'a, K: ArrowDictionaryKeyType, V> {
dictionary: &'a DictionaryArray<K>,
values: &'a V,
}
impl<K: ArrowDictionaryKeyType, V> Clone for TypedDictionaryArray<'_, K, V> {
fn clone(&self) -> Self {
*self
}
}
impl<K: ArrowDictionaryKeyType, V> Copy for TypedDictionaryArray<'_, K, V> {}
impl<K: ArrowDictionaryKeyType, V> std::fmt::Debug for TypedDictionaryArray<'_, K, V> {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
writeln!(f, "TypedDictionaryArray({:?})", self.dictionary)
}
}
impl<'a, K: ArrowDictionaryKeyType, V> TypedDictionaryArray<'a, K, V> {
pub fn keys(&self) -> &'a PrimitiveArray<K> {
self.dictionary.keys()
}
pub fn values(&self) -> &'a V {
self.values
}
}
impl<K: ArrowDictionaryKeyType, V: Sync> Array for TypedDictionaryArray<'_, K, V> {
fn as_any(&self) -> &dyn Any {
self.dictionary
}
fn to_data(&self) -> ArrayData {
self.dictionary.to_data()
}
fn into_data(self) -> ArrayData {
self.dictionary.into_data()
}
fn data_type(&self) -> &DataType {
self.dictionary.data_type()
}
fn slice(&self, offset: usize, length: usize) -> ArrayRef {
Arc::new(self.dictionary.slice(offset, length))
}
fn len(&self) -> usize {
self.dictionary.len()
}
fn is_empty(&self) -> bool {
self.dictionary.is_empty()
}
fn offset(&self) -> usize {
self.dictionary.offset()
}
fn nulls(&self) -> Option<&NullBuffer> {
self.dictionary.nulls()
}
fn logical_nulls(&self) -> Option<NullBuffer> {
self.dictionary.logical_nulls()
}
fn logical_null_count(&self) -> usize {
self.dictionary.logical_null_count()
}
fn is_nullable(&self) -> bool {
self.dictionary.is_nullable()
}
fn get_buffer_memory_size(&self) -> usize {
self.dictionary.get_buffer_memory_size()
}
fn get_array_memory_size(&self) -> usize {
self.dictionary.get_array_memory_size()
}
}
impl<K, V> IntoIterator for TypedDictionaryArray<'_, K, V>
where
K: ArrowDictionaryKeyType,
Self: ArrayAccessor,
{
type Item = Option<<Self as ArrayAccessor>::Item>;
type IntoIter = ArrayIter<Self>;
fn into_iter(self) -> Self::IntoIter {
ArrayIter::new(self)
}
}
impl<'a, K, V> ArrayAccessor for TypedDictionaryArray<'a, K, V>
where
K: ArrowDictionaryKeyType,
V: Sync + Send,
&'a V: ArrayAccessor,
<&'a V as ArrayAccessor>::Item: Default,
{
type Item = <&'a V as ArrayAccessor>::Item;
fn value(&self, index: usize) -> Self::Item {
assert!(
index < self.len(),
"Trying to access an element at index {} from a TypedDictionaryArray of length {}",
index,
self.len()
);
unsafe { self.value_unchecked(index) }
}
unsafe fn value_unchecked(&self, index: usize) -> Self::Item {
let val = self.dictionary.keys.value_unchecked(index);
let value_idx = val.as_usize();
match value_idx < self.values.len() {
true => self.values.value_unchecked(value_idx),
false => Default::default(),
}
}
}
pub trait AnyDictionaryArray: Array {
fn keys(&self) -> &dyn Array;
fn values(&self) -> &ArrayRef;
fn normalized_keys(&self) -> Vec<usize>;
fn with_values(&self, values: ArrayRef) -> ArrayRef;
}
impl<K: ArrowDictionaryKeyType> AnyDictionaryArray for DictionaryArray<K> {
fn keys(&self) -> &dyn Array {
&self.keys
}
fn values(&self) -> &ArrayRef {
self.values()
}
fn normalized_keys(&self) -> Vec<usize> {
let v_len = self.values().len();
assert_ne!(v_len, 0);
let iter = self.keys().values().iter();
iter.map(|x| x.as_usize().min(v_len - 1)).collect()
}
fn with_values(&self, values: ArrayRef) -> ArrayRef {
Arc::new(self.with_values(values))
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::cast::as_dictionary_array;
use crate::{Int16Array, Int32Array, Int8Array};
use arrow_buffer::{Buffer, ToByteSlice};
#[test]
fn test_dictionary_array() {
let value_data = ArrayData::builder(DataType::Int8)
.len(8)
.add_buffer(Buffer::from(
[10_i8, 11, 12, 13, 14, 15, 16, 17].to_byte_slice(),
))
.build()
.unwrap();
let keys = Buffer::from([2_i16, 3, 4].to_byte_slice());
let key_type = DataType::Int16;
let value_type = DataType::Int8;
let dict_data_type = DataType::Dictionary(Box::new(key_type), Box::new(value_type));
let dict_data = ArrayData::builder(dict_data_type.clone())
.len(3)
.add_buffer(keys.clone())
.add_child_data(value_data.clone())
.build()
.unwrap();
let dict_array = Int16DictionaryArray::from(dict_data);
let values = dict_array.values();
assert_eq!(value_data, values.to_data());
assert_eq!(DataType::Int8, dict_array.value_type());
assert_eq!(3, dict_array.len());
assert_eq!(0, dict_array.null_count());
assert_eq!(0, dict_array.values().null_count());
assert_eq!(dict_array.keys(), &Int16Array::from(vec![2_i16, 3, 4]));
let dict_data = ArrayData::builder(dict_data_type)
.len(2)
.offset(1)
.add_buffer(keys)
.add_child_data(value_data.clone())
.build()
.unwrap();
let dict_array = Int16DictionaryArray::from(dict_data);
let values = dict_array.values();
assert_eq!(value_data, values.to_data());
assert_eq!(DataType::Int8, dict_array.value_type());
assert_eq!(2, dict_array.len());
assert_eq!(dict_array.keys(), &Int16Array::from(vec![3_i16, 4]));
}
#[test]
fn test_dictionary_builder_append_many() {
let mut builder = PrimitiveDictionaryBuilder::<UInt8Type, UInt32Type>::new();
builder.append(1).unwrap();
builder.append_n(2, 2).unwrap();
builder.append_options(None, 2);
builder.append_options(Some(3), 3);
let array = builder.finish();
let values = array
.values()
.as_primitive::<UInt32Type>()
.iter()
.map(Option::unwrap)
.collect::<Vec<_>>();
assert_eq!(values, &[1, 2, 3]);
let keys = array.keys().iter().collect::<Vec<_>>();
assert_eq!(
keys,
&[
Some(0),
Some(1),
Some(1),
None,
None,
Some(2),
Some(2),
Some(2)
]
);
}
#[test]
fn test_string_dictionary_builder_append_many() {
let mut builder = StringDictionaryBuilder::<Int8Type>::new();
builder.append("a").unwrap();
builder.append_n("b", 2).unwrap();
builder.append_options(None::<&str>, 2);
builder.append_options(Some("c"), 3);
let array = builder.finish();
let values = array
.values()
.as_string::<i32>()
.iter()
.map(Option::unwrap)
.collect::<Vec<_>>();
assert_eq!(values, &["a", "b", "c"]);
let keys = array.keys().iter().collect::<Vec<_>>();
assert_eq!(
keys,
&[
Some(0),
Some(1),
Some(1),
None,
None,
Some(2),
Some(2),
Some(2)
]
);
}
#[test]
fn test_dictionary_array_fmt_debug() {
let mut builder = PrimitiveDictionaryBuilder::<UInt8Type, UInt32Type>::with_capacity(3, 2);
builder.append(12345678).unwrap();
builder.append_null();
builder.append(22345678).unwrap();
let array = builder.finish();
assert_eq!(
"DictionaryArray {keys: PrimitiveArray<UInt8>\n[\n 0,\n null,\n 1,\n] values: PrimitiveArray<UInt32>\n[\n 12345678,\n 22345678,\n]}\n",
format!("{array:?}")
);
let mut builder = PrimitiveDictionaryBuilder::<UInt8Type, UInt32Type>::with_capacity(20, 2);
for _ in 0..20 {
builder.append(1).unwrap();
}
let array = builder.finish();
assert_eq!(
"DictionaryArray {keys: PrimitiveArray<UInt8>\n[\n 0,\n 0,\n 0,\n 0,\n 0,\n 0,\n 0,\n 0,\n 0,\n 0,\n 0,\n 0,\n 0,\n 0,\n 0,\n 0,\n 0,\n 0,\n 0,\n 0,\n] values: PrimitiveArray<UInt32>\n[\n 1,\n]}\n",
format!("{array:?}")
);
}
#[test]
fn test_dictionary_array_from_iter() {
let test = vec!["a", "a", "b", "c"];
let array: DictionaryArray<Int8Type> = test
.iter()
.map(|&x| if x == "b" { None } else { Some(x) })
.collect();
assert_eq!(
"DictionaryArray {keys: PrimitiveArray<Int8>\n[\n 0,\n 0,\n null,\n 1,\n] values: StringArray\n[\n \"a\",\n \"c\",\n]}\n",
format!("{array:?}")
);
let array: DictionaryArray<Int8Type> = test.into_iter().collect();
assert_eq!(
"DictionaryArray {keys: PrimitiveArray<Int8>\n[\n 0,\n 0,\n 1,\n 2,\n] values: StringArray\n[\n \"a\",\n \"b\",\n \"c\",\n]}\n",
format!("{array:?}")
);
}
#[test]
fn test_dictionary_array_reverse_lookup_key() {
let test = vec!["a", "a", "b", "c"];
let array: DictionaryArray<Int8Type> = test.into_iter().collect();
assert_eq!(array.lookup_key("c"), Some(2));
let test = vec!["t3", "t3", "t2", "t2", "t1", "t3", "t4", "t1", "t0"];
let array: DictionaryArray<Int8Type> = test.into_iter().collect();
assert_eq!(array.lookup_key("t1"), Some(2));
assert_eq!(array.lookup_key("non-existent"), None);
}
#[test]
fn test_dictionary_keys_as_primitive_array() {
let test = vec!["a", "b", "c", "a"];
let array: DictionaryArray<Int8Type> = test.into_iter().collect();
let keys = array.keys();
assert_eq!(&DataType::Int8, keys.data_type());
assert_eq!(0, keys.null_count());
assert_eq!(&[0, 1, 2, 0], keys.values());
}
#[test]
fn test_dictionary_keys_as_primitive_array_with_null() {
let test = vec![Some("a"), None, Some("b"), None, None, Some("a")];
let array: DictionaryArray<Int32Type> = test.into_iter().collect();
let keys = array.keys();
assert_eq!(&DataType::Int32, keys.data_type());
assert_eq!(3, keys.null_count());
assert!(keys.is_valid(0));
assert!(!keys.is_valid(1));
assert!(keys.is_valid(2));
assert!(!keys.is_valid(3));
assert!(!keys.is_valid(4));
assert!(keys.is_valid(5));
assert_eq!(0, keys.value(0));
assert_eq!(1, keys.value(2));
assert_eq!(0, keys.value(5));
}
#[test]
fn test_dictionary_all_nulls() {
let test = vec![None, None, None];
let array: DictionaryArray<Int32Type> = test.into_iter().collect();
array
.into_data()
.validate_full()
.expect("All null array has valid array data");
}
#[test]
fn test_dictionary_iter() {
let values = Int8Array::from_iter_values([10_i8, 11, 12, 13, 14, 15, 16, 17]);
let keys = Int16Array::from_iter_values([2_i16, 3, 4]);
let dict_array = DictionaryArray::new(keys, Arc::new(values));
let mut key_iter = dict_array.keys_iter();
assert_eq!(2, key_iter.next().unwrap().unwrap());
assert_eq!(3, key_iter.next().unwrap().unwrap());
assert_eq!(4, key_iter.next().unwrap().unwrap());
assert!(key_iter.next().is_none());
let mut iter = dict_array
.values()
.as_any()
.downcast_ref::<Int8Array>()
.unwrap()
.take_iter(dict_array.keys_iter());
assert_eq!(12, iter.next().unwrap().unwrap());
assert_eq!(13, iter.next().unwrap().unwrap());
assert_eq!(14, iter.next().unwrap().unwrap());
assert!(iter.next().is_none());
}
#[test]
fn test_dictionary_iter_with_null() {
let test = vec![Some("a"), None, Some("b"), None, None, Some("a")];
let array: DictionaryArray<Int32Type> = test.into_iter().collect();
let mut iter = array
.values()
.as_any()
.downcast_ref::<StringArray>()
.unwrap()
.take_iter(array.keys_iter());
assert_eq!("a", iter.next().unwrap().unwrap());
assert!(iter.next().unwrap().is_none());
assert_eq!("b", iter.next().unwrap().unwrap());
assert!(iter.next().unwrap().is_none());
assert!(iter.next().unwrap().is_none());
assert_eq!("a", iter.next().unwrap().unwrap());
assert!(iter.next().is_none());
}
#[test]
fn test_dictionary_key() {
let keys = Int8Array::from(vec![Some(2), None, Some(1)]);
let values = StringArray::from(vec!["foo", "bar", "baz", "blarg"]);
let array = DictionaryArray::new(keys, Arc::new(values));
assert_eq!(array.key(0), Some(2));
assert_eq!(array.key(1), None);
assert_eq!(array.key(2), Some(1));
}
#[test]
fn test_try_new() {
let values: StringArray = [Some("foo"), Some("bar"), Some("baz")]
.into_iter()
.collect();
let keys: Int32Array = [Some(0), Some(2), None, Some(1)].into_iter().collect();
let array = DictionaryArray::new(keys, Arc::new(values));
assert_eq!(array.keys().data_type(), &DataType::Int32);
assert_eq!(array.values().data_type(), &DataType::Utf8);
assert_eq!(array.null_count(), 1);
assert_eq!(array.logical_null_count(), 1);
assert!(array.keys().is_valid(0));
assert!(array.keys().is_valid(1));
assert!(array.keys().is_null(2));
assert!(array.keys().is_valid(3));
assert_eq!(array.keys().value(0), 0);
assert_eq!(array.keys().value(1), 2);
assert_eq!(array.keys().value(3), 1);
assert_eq!(
"DictionaryArray {keys: PrimitiveArray<Int32>\n[\n 0,\n 2,\n null,\n 1,\n] values: StringArray\n[\n \"foo\",\n \"bar\",\n \"baz\",\n]}\n",
format!("{array:?}")
);
}
#[test]
#[should_panic(expected = "Invalid dictionary key 3 at index 1, expected 0 <= key < 2")]
fn test_try_new_index_too_large() {
let values: StringArray = [Some("foo"), Some("bar")].into_iter().collect();
let keys: Int32Array = [Some(0), Some(3)].into_iter().collect();
DictionaryArray::new(keys, Arc::new(values));
}
#[test]
#[should_panic(expected = "Invalid dictionary key -100 at index 0, expected 0 <= key < 2")]
fn test_try_new_index_too_small() {
let values: StringArray = [Some("foo"), Some("bar")].into_iter().collect();
let keys: Int32Array = [Some(-100)].into_iter().collect();
DictionaryArray::new(keys, Arc::new(values));
}
#[test]
#[should_panic(expected = "DictionaryArray's data type must match, expected Int64 got Int32")]
fn test_from_array_data_validation() {
let a = DictionaryArray::<Int32Type>::from_iter(["32"]);
let _ = DictionaryArray::<Int64Type>::from(a.into_data());
}
#[test]
fn test_into_primitive_dict_builder() {
let values = Int32Array::from_iter_values([10_i32, 12, 15]);
let keys = Int8Array::from_iter_values([1_i8, 0, 2, 0]);
let dict_array = DictionaryArray::new(keys, Arc::new(values));
let boxed: ArrayRef = Arc::new(dict_array);
let col: DictionaryArray<Int8Type> = as_dictionary_array(&boxed).clone();
drop(boxed);
let mut builder = col.into_primitive_dict_builder::<Int32Type>().unwrap();
let slice = builder.values_slice_mut();
assert_eq!(slice, &[10, 12, 15]);
slice[0] = 4;
slice[1] = 2;
slice[2] = 1;
let values = Int32Array::from_iter_values([4_i32, 2, 1]);
let keys = Int8Array::from_iter_values([1_i8, 0, 2, 0]);
let expected = DictionaryArray::new(keys, Arc::new(values));
let new_array = builder.finish();
assert_eq!(expected, new_array);
}
#[test]
fn test_into_primitive_dict_builder_cloned_array() {
let values = Int32Array::from_iter_values([10_i32, 12, 15]);
let keys = Int8Array::from_iter_values([1_i8, 0, 2, 0]);
let dict_array = DictionaryArray::new(keys, Arc::new(values));
let boxed: ArrayRef = Arc::new(dict_array);
let col: DictionaryArray<Int8Type> = DictionaryArray::<Int8Type>::from(boxed.to_data());
let err = col.into_primitive_dict_builder::<Int32Type>();
let returned = err.unwrap_err();
let values = Int32Array::from_iter_values([10_i32, 12, 15]);
let keys = Int8Array::from_iter_values([1_i8, 0, 2, 0]);
let expected = DictionaryArray::new(keys, Arc::new(values));
assert_eq!(expected, returned);
}
#[test]
fn test_occupancy() {
let keys = Int32Array::new((100..200).collect(), None);
let values = Int32Array::from(vec![0; 1024]);
let dict = DictionaryArray::new(keys, Arc::new(values));
for (idx, v) in dict.occupancy().iter().enumerate() {
let expected = (100..200).contains(&idx);
assert_eq!(v, expected, "{idx}");
}
let keys = Int32Array::new(
(0..100).collect(),
Some((0..100).map(|x| x % 4 == 0).collect()),
);
let values = Int32Array::from(vec![0; 1024]);
let dict = DictionaryArray::new(keys, Arc::new(values));
for (idx, v) in dict.occupancy().iter().enumerate() {
let expected = idx % 4 == 0 && idx < 100;
assert_eq!(v, expected, "{idx}");
}
}
#[test]
fn test_iterator_nulls() {
let keys = Int32Array::new(
vec![0, 700, 1, 2].into(),
Some(NullBuffer::from(vec![true, false, true, true])),
);
let values = Int32Array::from(vec![Some(50), None, Some(2)]);
let dict = DictionaryArray::new(keys, Arc::new(values));
let values: Vec<_> = dict
.downcast_dict::<Int32Array>()
.unwrap()
.into_iter()
.collect();
assert_eq!(values, &[Some(50), None, None, Some(2)])
}
#[test]
fn test_normalized_keys() {
let values = vec![132, 0, 1].into();
let nulls = NullBuffer::from(vec![false, true, true]);
let keys = Int32Array::new(values, Some(nulls));
let dictionary = DictionaryArray::new(keys, Arc::new(Int32Array::new_null(2)));
assert_eq!(&dictionary.normalized_keys(), &[1, 0, 1])
}
}