Viall is a new, type of variable that tries to be very close to old Map(). In essence, classic Map allow for an association between unique keys and their values, but lack an iterative interface. For example, how can you transform every value or filter the entries in a Map easily? This is the point of the Viall class! We are combining best functionality of Maps and Arrays in one.
Many of the methods on Viall
are based on their namesake in Array
. One of them is find
:
// Assume we have an array of cars and a viall of the same cars.
someArray.find(car => car.color === 'black');
someViall.find(car => car.color === 'black');
The interface of the callback function is very similar between the two. For arrays, callbacks are usually passed the parameters (value, index, array)
, where value is the value it iterated to, index is the current index, and array is the array itself. For vialls, you would have (value, key, viall)
. Here, value is the same, but key is the key of the value, and viall is the viall itself instead.
Methods that follow this philosophy of staying close to the Array
interface are as follows:
find
filter
map
-
isEvery
- corresponds to the<Array>.every
-
isAny
- corresponds to the<Array>.some
concat
-
sort
- Learn how Vialls are sorted
filter()
&map()
returns an Array of values instead of a Viall!
You can easily convert any Viall to Array if you like to:
import Viall from 'viall';
const myViall: Viall<number> = new Viall();
// <TS> Add value type ☝️
// You can add own interfaces, types, etc.
// Viall's values can store any type of data.
myViall.set('A', 1).set('B', 2).set('C', 3);
// Grab everything
const data = myViall.entries();
// => [['A', 1], ['B', 2], ['C', 3]]
// I want just keys!
const keys = myViall.keys();
// => ['A', 'B', 'C']
// How about values? No problem!
const values = myViall.values();
// => [1, 2, 3]
⏱️ Remember that this convertion can take some time on really large amount of values! (like milions of objects)
Some methods are not from Array
and are completely new to standard JavaScript.
// Return random value from Viall.
myViall.random();
// Grabs first value from Viall.
myViall.first();
// Grabs first 5 values.
myViall.first(5);
// Similar to first(), but from the end.
myViall.last();
myViall.last(2);
// Removes from the viall anything that meets a criteria.
// Sort of like filter, but in-place.
myViall.sweep(book => book.price > 100);
Vialls are generally over 2x times faster than regular Maps and uses less memory. How this is possible?
⚙️
Vialls
operates on special, hidden object instead reusing already existingMap()
. Each method likeget()
orset()
is in reality a set of instructions that are not exactly the same like in regular Map, but works in very similar way - final result is the same. Like always - there are pros & cons of this idea:
❌ CONS | ✅ PROS |
---|---|
Key type is limited to number or string (Automatically rewrites to string type) |
Highly effective (faster) |
sort() method works only onvalues with string type key |
Lightweight (less memory usage) |
Can easily convert to Array
|
|
Supports a large range of filters | |
Contains extra methods for easier usage | |
Works without self replication of own data | |
Full TypeScript support |
💽 I want to show you the speed/capacity difference. I made really simple capacity test that just loads 1,000,000 keys & values (ints) into both - Map & Viall
// Clear, before test (pure Node.js)
rss: 18MB
heapTotal: 4MB
heapUsed: 3MB
external: 0MB
arrayBuffers: 0MB
// Using regular Map
rss: 73MB
heapTotal: 59MB
heapUsed: 43MB
external: 0MB
arrayBuffers: 0MB
// Using Viall
rss: 41MB
heapTotal: 31MB
heapUsed: 22MB
external: 0MB
arrayBuffers: 0MB
⏱️ Additionally, I registered times of each loop:
-
Map
- First try:
421.093ms
- Second try:
409.127ms
- Third try:
637.104ms
- First try:
-
Viall
- First try:
164.221ms
- Second try:
114.025ms
- Third try:
182.431ms
- First try:
Of course, it strongly depends from type of processor it was run on. I used just MacBook Air with CPU: Intel(R) Core(TM) i3-1000NG4 CPU @ 1.10GHz (4 cores)
That gonna most likely never happen while normal usage, but you should know that Viall works on original data set instead making self replication over and over like Map does. During my work I never run into any issue with damaging data inside, but for safety, make a copy before you start making brutal operations on larger scale.
Example way how you should use a copy:
interface data {
health: number,
mana: number,
stamina: number
money: number
isFighting: boolean
inventory: Array<...>
}
const characters: Viall<data> = new Viall();
characters.set({...});
characters.set({...});
characters.set({...});
// You can safely read/write, map, filter, etc.
// But you cannot be sure what gonna happen when you push Viall
// To other, unknown 3rd-party property...
dangerousOperation(characters); // ❌ Bad idea
const chars = characters.copy();
dangerousOperation(chars); // 👍 Better
// => Even if you damage data, hey! Thay was just a copy :)