NAME

Sidef::Types::Set::Bag - A multiset (bag) data structure for Sidef

DESCRIPTION

This class implements a multiset (also known as a bag), which is a collection that allows duplicate elements and tracks the frequency of each unique element. Unlike a regular Set where each element appears at most once, a Bag maintains a count for each element, making it useful for frequency analysis and operations that need to preserve multiplicity.

A Bag is essentially a mapping from elements to their frequencies, where the frequency represents how many times each element appears in the collection.

SYNOPSIS

var a = Bag(1, 1, 2, 3)
var b = Bag(1, 4, 3, 5)

say (a | b)     #=> Bag(1, 1, 2, 3, 4, 5)
say (a ^ b)     #=> Bag(1, 2, 4, 5)
say (a & b)     #=> Bag(1, 3)
say (a - b)     #=> Bag(1, 2)
say (a + b)     #=> Bag(1, 1, 1, 2, 3, 3, 4, 5)

say a.count(1)  #=> 2
say a.elems     #=> 3
say a.len       #=> 4

say a.keys      #=> [1, 2, 3]
say a.freq      #=> [[1, 2], [2, 1], [3, 1]]

INHERITS

Inherits methods from:

* Sidef::Types::Set::Set

METHODS

&

a & b

Returns the intersection of two bags. The resulting bag contains elements that appear in both bags, with the frequency being the minimum of the frequencies in the two bags.

Example:

Bag(1, 1, 2, 3) & Bag(1, 2, 2, 4)  #=> Bag(1, 2)

Aliases: , and, intersection

+

a + b

Returns the sum (concatenation) of two bags. The resulting bag contains all elements from both bags, with frequencies added together.

Example:

Bag(1, 2) + Bag(2, 3)  #=> Bag(1, 2, 2, 3)

Aliases: concat

-

a - b

Returns the difference of two bags. The resulting bag contains elements from the first bag with their frequencies reduced by the frequencies in the second bag. Elements are removed entirely if their frequency becomes zero or negative.

Example:

Bag(1, 1, 2, 3) - Bag(1, 3)  #=> Bag(1, 2)

Aliases: , sub, diff, difference

...

a ... b

Returns an array containing all elements from the bag expanded according to their frequencies, up to the range specified.

Aliases: to_list

<<

a << b

Adds an element to the bag, incrementing its frequency by 1. Returns the modified bag.

Example:

var bag = Bag(1, 2)
bag << 2              #=> Bag(1, 2, 2)

Aliases: add, push, append

^

a ^ b

Returns the symmetric difference of two bags. The resulting bag contains elements that appear in either bag but not in both (with equal frequency). Frequencies are calculated as the absolute difference.

Example:

Bag(1, 1, 2) ^ Bag(1, 3)  #=> Bag(1, 2, 3)

Aliases: xor, symdiff, symmetric_difference

|

a | b

Returns the union of two bags. The resulting bag contains all elements from both bags, with the frequency being the maximum of the frequencies in the two bags.

Example:

Bag(1, 1, 2) | Bag(1, 3, 3)  #=> Bag(1, 1, 2, 3, 3)

Aliases: , or, union

a ∋ b

Returns true if the bag contains the specified element (at least once), false otherwise.

Example:

Bag(1, 2, 3) ∋ 2  #=> true
Bag(1, 2, 3) ∋ 5  #=> false

Aliases: has, exists, has_key, haskey, contain, include, contains, includes

a ∌ b

Returns true if the bag does not contain the specified element, false otherwise. This is the negation of the ∋ operator.

Example:

Bag(1, 2, 3) ∌ 5  #=> true
Bag(1, 2, 3) ∌ 2  #=> false

a ≠ b

Returns true if two bags are not equal (contain different elements or different frequencies), false otherwise.

Example:

Bag(1, 2) ≠ Bag(1, 2, 2)  #=> true

Aliases: !=, ne

a ≡ b

Returns true if two bags are equal (contain the same elements with the same frequencies), false otherwise.

Example:

Bag(1, 2, 2) ≡ Bag(2, 1, 2)  #=> true

Aliases: ==, eq

a ≤ b

Returns true if bag 'a' is a subset of bag 'b' (every element in 'a' appears in 'b' with at least the same frequency), false otherwise.

Example:

Bag(1, 2) ≤ Bag(1, 2, 2, 3)  #=> true

Aliases: , <=, is_subset

a ≥ b

Returns true if bag 'a' is a superset of bag 'b' (every element in 'b' appears in 'a' with at least the same frequency), false otherwise.

Example:

Bag(1, 2, 2, 3) ≥ Bag(1, 2)  #=> true

Aliases: , >=, is_superset

add_kv

self.add_kv(obj, n)

Adds an element to the bag with a specific frequency increment. Increases the frequency of 'obj' by 'n'. Returns the modified bag.

Example:

var bag = Bag(1, 2)
bag.add_kv(2, 3)  #=> Bag(1, 2, 2, 2, 2)

Aliases: push_kv, add_pair, append_kv, push_pair, append_pair

add_kvs

self.add_kvs(*pairs)

Adds multiple elements with their frequencies to the bag. Accepts pairs of [element, frequency] as arguments. Returns the modified bag.

Example:

var bag = Bag(1)
bag.add_kvs([2, 3], [3, 2])  #=> Bag(1, 2, 2, 2, 3, 3)

Aliases: push_kvs, add_pairs, append_kvs, push_pairs, append_pairs

clone

self.clone

Returns a shallow copy of the bag with the same elements and frequencies.

Example:

var a = Bag(1, 2, 3)
var b = a.clone
b << 4
say a  #=> Bag(1, 2, 3)
say b  #=> Bag(1, 2, 3, 4)

collect

self.collect(block)

Applies a transformation block to each element in the bag (respecting multiplicity) and returns a new bag with the transformed elements.

Example:

Bag(1, 2, 2).collect { _ * 2 }  #=> Bag(2, 4, 4)

contains_all

self.contains_all(*objects)

Returns true if the bag contains all of the specified objects (at least once each), false otherwise.

Example:

Bag(1, 2, 3, 3).contains_all(1, 3)  #=> true
Bag(1, 2, 3).contains_all(1, 4)     #=> false

count_by

self.count_by(block)

Groups elements by the result of applying the block to each element (respecting multiplicity) and returns a new bag where keys are the block results and frequencies are the counts.

Example:

Bag(1, 2, 3, 4).count_by { _ % 2 }  #=> Bag(0, 0, 1, 1)

delete

self.delete(*objects)

Removes one occurrence of each specified object from the bag. Decrements the frequency by 1 for each object. Returns the modified bag.

Example:

Bag(1, 1, 2, 3).delete(1, 2)  #=> Bag(1, 3)

Aliases: remove, discard

delete_all

self.delete_all(*objects)

Removes all occurrences of each specified object from the bag. Returns the modified bag.

Example:

Bag(1, 1, 2, 3).delete_all(1, 2)  #=> Bag(3)

Aliases: remove_all, discard_all

delete_first_if

self.delete_first_if(block)

Removes the first element (according to iteration order) that satisfies the condition in the block. Decrements its frequency by 1. Returns the modified bag.

Example:

Bag(1, 2, 3, 4).delete_first_if { _ > 2 }  #=> Bag(1, 2, 4)

delete_if

self.delete_if(block)

Removes all elements that satisfy the condition in the block. Removes all occurrences of matching elements. Returns the modified bag.

Example:

Bag(1, 2, 2, 3, 4).delete_if { _ % 2 == 0 }  #=> Bag(1, 3)

delete_key

self.delete_key(obj)

Completely removes the specified key (element) from the bag along with all its occurrences. Returns the modified bag.

Example:

Bag(1, 1, 2, 3).delete_key(1)  #=> Bag(2, 3)

Aliases: remove_key, discard_key

dump

self.dump

Returns a string representation of the bag suitable for debugging or serialization, showing the internal structure.

Example:

Bag(1, 2, 2).dump  #=> "Bag(1, 2, 2)"

each

self.each(block)

Iterates over each element in the bag (respecting multiplicity) and executes the block for each occurrence. Returns the bag.

Example:

Bag(1, 2, 2).each { say _ }
# Prints: 1, 2, 2

each_2d

self.each_2d(block)

Iterates over the bag as a 2D structure, passing pairs of [element, frequency] to the block. Returns the bag.

Example:

Bag(1, 2, 2).each_2d { |k, v| say "#{k}: #{v}" }
# Prints: 1: 1, 2: 2

each_kv

self.each_kv(block)

Iterates over key-value pairs in the bag, passing the element and its frequency to the block. Returns the bag.

Example:

Bag(1, 2, 2, 3).each_kv { |k, v| say "#{k} appears #{v} times" }

elems

self.elems

Returns the number of unique elements (distinct keys) in the bag.

Example:

Bag(1, 1, 2, 3).elems  #=> 3

Aliases: keys_len

freq

self.freq

Returns an array of [element, frequency] pairs for all elements in the bag.

Example:

Bag(1, 1, 2, 3).freq  #=> [[1, 2], [2, 1], [3, 1]]

get

self.get(obj)

Returns the frequency (count) of the specified element in the bag. Returns 0 if the element is not present.

Example:

Bag(1, 1, 2, 3).get(1)  #=> 2
Bag(1, 1, 2, 3).get(5)  #=> 0

Aliases: count

grep

self.grep(block)

Returns a new bag containing only the elements (with their frequencies) that satisfy the condition in the block.

Example:

Bag(1, 2, 2, 3, 4).grep { _ % 2 == 0 }  #=> Bag(2, 2, 4)

Aliases: select

grep_2d

self.grep_2d(block)

Filters the bag by applying the block to [element, frequency] pairs. Returns a new bag with pairs that satisfy the condition.

Example:

Bag(1, 2, 2, 3).grep_2d { |k, v| v > 1 }  #=> Bag(2, 2)

grep_kv

self.grep_kv(block)

Filters the bag by applying the block to element-frequency pairs. Returns a new bag with elements whose key-value pairs satisfy the condition.

Example:

Bag(1, 2, 2, 3, 3, 3).grep_kv { |k, v| k == v }  #=> Bag(3, 3, 3)

iter

self.iter

Returns an iterator object that can be used to iterate over the elements in the bag (respecting multiplicity).

Example:

var iter = Bag(1, 2, 2).iter
say iter.next  #=> 1
say iter.next  #=> 2
say iter.next  #=> 2

join

self.join(*rest)

Converts the bag elements to strings and joins them using the specified separator. Multiple arguments are treated as additional separators for nested structures.

Example:

Bag(1, 2, 2, 3).join(", ")  #=> "1, 2, 2, 3"

keys

self.keys

Returns an array of unique elements (keys) in the bag, without their frequencies.

Example:

Bag(1, 1, 2, 3).keys  #=> [1, 2, 3]

kv

self.kv

Returns an array of [element, frequency] pairs for all elements in the bag. Similar to freq().

Example:

Bag(1, 1, 2).kv  #=> [[1, 2], [2, 1]]

Aliases: pairs

len

self.len

Returns the total number of elements in the bag, counting multiplicities (sum of all frequencies).

Example:

Bag(1, 1, 2, 3).len  #=> 4

Aliases: size, length

map

self.map(block)

Applies the block to each element in the bag (respecting multiplicity) and returns a new bag with the results.

Example:

Bag(1, 2, 2).map { _ * 2 }  #=> Bag(2, 4, 4)

map_2d

self.map_2d(block)

Applies the block to [element, frequency] pairs and returns a new bag constructed from the results.

Example:

Bag(1, 2, 2).map_2d { |k, v| [k * 2, v] }  #=> Bag(2, 4, 4)

map_kv

self.map_kv(block)

Applies the block to element-frequency pairs and returns a new bag constructed from the results.

Example:

Bag(1, 2).map_kv { |k, v| [k + 1, v * 2] }  #=> Bag(2, 2, 3, 3)

max

self.max

Returns the maximum element in the bag (ignoring frequencies).

Example:

Bag(1, 5, 3, 3).max  #=> 5

max_by

self.max_by(block)

Returns the element for which the block returns the maximum value (ignoring frequencies).

Example:

Bag(1, 2, 3).max_by { _ * -1 }  #=> 1

min

self.min

Returns the minimum element in the bag (ignoring frequencies).

Example:

Bag(5, 1, 3, 3).min  #=> 1

min_by

self.min_by(block)

Returns the element for which the block returns the minimum value (ignoring frequencies).

Example:

Bag(1, 2, 3).min_by { _ * -1 }  #=> 3

new

self.new

Creates a new empty bag, or a bag initialized with the provided elements.

Example:

var bag = Bag.new
var bag2 = Bag.new(1, 2, 2, 3)  #=> Bag(1, 2, 2, 3)

Aliases: call

pop

self.pop

Removes and returns an arbitrary element from the bag. Decrements its frequency by 1. The bag must not be empty.

Example:

var bag = Bag(1, 2, 2)
bag.pop  #=> returns one element, e.g., 1

set_kv

self.set_kv(obj, n)

Sets the frequency of an element to a specific value. If n is 0 or negative, the element is removed. Returns the modified bag.

Example:

var bag = Bag(1, 2, 2)
bag.set_kv(2, 5)  #=> Bag(1, 2, 2, 2, 2, 2)

Aliases: update_kv, update_pair, replace_pair

set_kvs

self.set_kvs(*pairs)

Sets the frequencies of multiple elements. Accepts pairs of [element, frequency]. Returns the modified bag.

Example:

var bag = Bag(1)
bag.set_kvs([1, 3], [2, 2])  #=> Bag(1, 1, 1, 2, 2)

Aliases: update_kvs, update_pairs, replace_pairs

shift

self.shift

Removes and returns an arbitrary element from the bag (typically the first in iteration order). Decrements its frequency by 1. The bag must not be empty.

Example:

var bag = Bag(1, 2, 2)
bag.shift  #=> returns one element, e.g., 1

sort

self.sort(block)

Returns an array of elements sorted according to the optional comparison block. Elements are expanded according to their frequencies.

Example:

Bag(3, 1, 2, 2).sort  #=> [1, 2, 2, 3]
Bag(3, 1, 2).sort { |a, b| b <=> a }  #=> [3, 2, 1]

sort_by

self.sort_by(block)

Returns an array of elements sorted by the result of applying the block to each element. Elements are expanded according to their frequencies.

Example:

Bag(1, 2, 3, 3).sort_by { _ * -1 }  #=> [3, 3, 2, 1]

to_a

self.to_a

Converts the bag to an array, expanding all elements according to their frequencies.

Example:

Bag(1, 2, 2, 3).to_a  #=> [1, 2, 2, 3]

Aliases: expand, to_array

to_bag

self.to_bag

Returns the bag itself (identity operation).

Example:

var bag = Bag(1, 2, 3)
bag.to_bag  #=> Bag(1, 2, 3)

top

self.top(n)

Returns an array of the top n most common elements with their frequencies, as [element, frequency] pairs, sorted by frequency in descending order.

Example:

Bag(1, 2, 2, 3, 3, 3).top(2)  #=> [[3, 3], [2, 2]]

Aliases: most_common

to_set

self.to_set

Converts the bag to a set, discarding frequency information and keeping only unique elements.

Example:

Bag(1, 1, 2, 3).to_set  #=> Set(1, 2, 3)

uniq

self.uniq

Returns a new bag with all elements having a frequency of 1 (effectively converting it to behave like a set while maintaining bag type).

Example:

Bag(1, 1, 2, 3, 3).uniq  #=> Bag(1, 2, 3)

Aliases: unique

values

self.values

Returns an array of all frequency values in the bag.

Example:

Bag(1, 1, 2, 3).values  #=> [2, 1, 1]

SEE ALSO

Sidef::Types::Set::Set

AUTHOR

Daniel "Trizen" Șuteu

LICENSE

This library is free software; you can redistribute it and/or modify it under the same terms as Sidef itself.