This provides a general overview of the underlying workings of a WeightedList
, which remains the same across both Python and C#. For language-specific walkthroughs, visit their respective folders.
A WeightedList
, as its name should indicate, is an extension of a regular list and is intended to be used in a similar way. As such, it inherits many properties and methods from a list, so if you’re familiar with lists then a weighted list shouldn’t be too difficult to pick up.
The key difference is that, instead of containing the values directly like a list, a WeightedList
stores them as WeightedItem
objects with value and weight attributes. This is a very lightweight class which only serves to contain these 2 attributes, so it can be helpful to think of a WeightedItem
as simply a 2-item tuple (that is mutable). Manipulating the contents of the WeightedList
revolves around handling WeightedItem
s.
WeightedList
offers several ways to pass in its data for different circumstances.
The cleanest way1 is by passing the data as tuples.
Python
wl = WeightedList(
(2, "sup"),
(3, "nova"),
)
C#
WeightedList<string, int> wl = new(
(2, "sup"),
(3, "nova")
);
Important
The weight comes before the value only for tuples. This allows the weights to align nicely so it’s clear which value they correspond to. It may seem counter-intuitive at first, but comes in immensely helpful when handling long weighted lists holding values all with varying lengths.
Both the Python and C# implementations provide the option to use WeightedItem
s, though this is not recommended since it is significantly more verbose than any other method.
Python
wl = WeightedList(
WeightedList.WeightedItem("sup", 2),
WeightedList.WeightedItem("nova", 3),
)
C#
WeightedList<string, int> wl = new(
new WeightedItem<string, int>(2, "sup"),
new WeightedItem<string, int>(3, "nova")
);
While you would never want to write this code explicitly, support for passing in data as
WeightedItem
s is still entirely necessary, since it allows data from otherWeightedList
s to be used.
If passing in data as a dictionary, each key-value pair represents a WeightedItem
, with the key and value corresponding to the item’s value and weight respectively.
Python
wl = WeightedList({
"sup": 2,
"nova": 3,
})
C#
Dictionary<string, int> data = new {
["sup"] = 2,
["nova"] = 3
};
WeightedList<string, int> wl = new(data);
Tip
If you haven’t read the rationale, now would be a good time to do so, since it illustrates the underlying concept behind the following implementation.
Perhaps the most confusing aspect of a WeightedList
is how its indexing works. Unlike a regular list, a WeightedList
uses weighted indexing.2 Essentially, imagine each value is repeated a number of times in the list equal to its weight. So for a WeightedList
containing "sup"
with a weight of 2
and "nova"
with a weight of 3
, its indices would work like so:
index | 0 | 1 | 2 | 3 | 4 |
---|---|---|---|---|---|
value | sup | sup | nova | nova | nova |
This weighted indexing is what allows the weighted randomisation to occur. Notice this also means it is unclear what the length of the WeightedList
should be defined as – so instead, it has a ‘total values’ property to count the number of distinct items, and a ‘total weights’ property to count the total weight of all the items.
While the Python and C# implementations are very similar, they have some significant differences.
- The Python
WeightedList
is a direct subclass oflist
, and either inherits or overrides all of its attributes and methods. The C#WeightedList<>
implements most of the methods and interfaces ofList<>
, but is not a subclass. - The Python
WeightedList
is the data, so methods manipulate the data viaself.method()
. The C#WeightedList<>
contains the data in a private_data
field, so methods manipulate the data via_data.Method()
. Externally, this makes no difference to how the 2 versions function. - The Python
WeightedItem
is an internal class ofWeightedList
, so is accessed viaWeightedList.WeightedItem
. The C#WeightedItem<>
is a standalone class defined in the same file as theWeightedList<>
class. - The C#
WeightedList<>
is strongly typed, so can only hold values of a single type (unless boxing them asobject
s), but also supports non-integer weights.