push/pop/shift/unshift (and fix sort()
This commit is contained in:
parent
2abf3558d5
commit
a8fd79a990
|
|
@ -1,3 +1,5 @@
|
||||||
|
import { type Value, toValue, toNull } from 'reefvm'
|
||||||
|
|
||||||
export const list = {
|
export const list = {
|
||||||
slice: (list: any[], start: number, end?: number) => list.slice(start, end),
|
slice: (list: any[], start: number, end?: number) => list.slice(start, end),
|
||||||
map: async (list: any[], cb: Function) => {
|
map: async (list: any[], cb: Function) => {
|
||||||
|
|
@ -40,9 +42,41 @@ export const list = {
|
||||||
return true
|
return true
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// mutating
|
||||||
|
push: (list: Value, item: Value) => {
|
||||||
|
if (list.type !== 'array') return toNull()
|
||||||
|
return toValue(list.value.push(item))
|
||||||
|
},
|
||||||
|
pop: (list: Value) => {
|
||||||
|
if (list.type !== 'array') return toNull()
|
||||||
|
return toValue(list.value.pop())
|
||||||
|
},
|
||||||
|
shift: (list: Value) => {
|
||||||
|
if (list.type !== 'array') return toNull()
|
||||||
|
return toValue(list.value.shift())
|
||||||
|
},
|
||||||
|
unshift: (list: Value, item: Value) => {
|
||||||
|
if (list.type !== 'array') return toNull()
|
||||||
|
return toValue(list.value.unshift(item))
|
||||||
|
},
|
||||||
|
splice: (list: Value, start: Value, deleteCount: Value, ...items: Value[]) => {
|
||||||
|
const realList = list.value as any[]
|
||||||
|
const realStart = start.value as number
|
||||||
|
const realDeleteCount = deleteCount.value as number
|
||||||
|
const realItems = items.map(item => item.value)
|
||||||
|
return toValue(realList.splice(realStart, realDeleteCount, ...realItems))
|
||||||
|
},
|
||||||
|
|
||||||
// sequence operations
|
// sequence operations
|
||||||
reverse: (list: any[]) => list.slice().reverse(),
|
reverse: (list: any[]) => list.slice().reverse(),
|
||||||
sort: (list: any[], cb?: (a: any, b: any) => number) => list.slice().sort(cb),
|
sort: async (list: any[], cb?: (a: any, b: any) => number) => {
|
||||||
|
const arr = [...list]
|
||||||
|
if (!cb) return arr.sort()
|
||||||
|
for (let i = 0; i < arr.length; i++)
|
||||||
|
for (let j = i + 1; j < arr.length; j++)
|
||||||
|
if ((await cb(arr[i], arr[j])) > 0) [arr[i], arr[j]] = [arr[j], arr[i]]
|
||||||
|
return arr
|
||||||
|
},
|
||||||
concat: (...lists: any[][]) => lists.flat(1),
|
concat: (...lists: any[][]) => lists.flat(1),
|
||||||
flatten: (list: any[], depth: number = 1) => list.flat(depth),
|
flatten: (list: any[], depth: number = 1) => list.flat(depth),
|
||||||
unique: (list: any[]) => Array.from(new Set(list)),
|
unique: (list: any[]) => Array.from(new Set(list)),
|
||||||
|
|
@ -86,4 +120,13 @@ export const list = {
|
||||||
}
|
}
|
||||||
return groups
|
return groups
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// raw functions deal directly in Value types, meaning we can modify collection
|
||||||
|
// careful - they MUST return a Value!
|
||||||
|
; (list.splice as any).raw = true
|
||||||
|
; (list.push as any).raw = true
|
||||||
|
; (list.pop as any).raw = true
|
||||||
|
; (list.shift as any).raw = true
|
||||||
|
; (list.unshift as any).raw = true
|
||||||
|
|
@ -341,6 +341,84 @@ describe('collections', () => {
|
||||||
await expect(`list.index-of [1 2 3] 5`).toEvaluateTo(-1, globals)
|
await expect(`list.index-of [1 2 3] 5`).toEvaluateTo(-1, globals)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
test('list.push adds to end and mutates array', async () => {
|
||||||
|
await expect(`arr = [1 2]; list.push arr 3; arr`).toEvaluateTo([1, 2, 3], globals)
|
||||||
|
})
|
||||||
|
|
||||||
|
test('list.push returns the size of the array', async () => {
|
||||||
|
await expect(`arr = [1 2]; arr | list.push 3`).toEvaluateTo(3, globals)
|
||||||
|
})
|
||||||
|
|
||||||
|
test('list.pop removes from end and mutates array', async () => {
|
||||||
|
await expect(`arr = [1 2 3]; list.pop arr; arr`).toEvaluateTo([1, 2], globals)
|
||||||
|
})
|
||||||
|
|
||||||
|
test('list.pop returns removed element', async () => {
|
||||||
|
await expect(`list.pop [1 2 3]`).toEvaluateTo(3, globals)
|
||||||
|
})
|
||||||
|
|
||||||
|
test('list.pop returns null for empty array', async () => {
|
||||||
|
await expect(`list.pop []`).toEvaluateTo(null, globals)
|
||||||
|
})
|
||||||
|
|
||||||
|
test('list.shift removes from start and mutates array', async () => {
|
||||||
|
await expect(`arr = [1 2 3]; list.shift arr; arr`).toEvaluateTo([2, 3], globals)
|
||||||
|
})
|
||||||
|
|
||||||
|
test('list.shift returns removed element', async () => {
|
||||||
|
await expect(`list.shift [1 2 3]`).toEvaluateTo(1, globals)
|
||||||
|
})
|
||||||
|
|
||||||
|
test('list.shift returns null for empty array', async () => {
|
||||||
|
await expect(`list.shift []`).toEvaluateTo(null, globals)
|
||||||
|
})
|
||||||
|
|
||||||
|
test('list.unshift adds to start and mutates array', async () => {
|
||||||
|
await expect(`arr = [2 3]; list.unshift arr 1; arr`).toEvaluateTo([1, 2, 3], globals)
|
||||||
|
})
|
||||||
|
|
||||||
|
test('list.unshift returns the length of the array', async () => {
|
||||||
|
await expect(`arr = [2 3]; arr | list.unshift 1`).toEvaluateTo(3, globals)
|
||||||
|
})
|
||||||
|
|
||||||
|
test('list.splice removes elements and mutates array', async () => {
|
||||||
|
await expect(`arr = [1 2 3 4 5]; list.splice arr 1 2; arr`).toEvaluateTo([1, 4, 5], globals)
|
||||||
|
})
|
||||||
|
|
||||||
|
test('list.splice returns removed elements', async () => {
|
||||||
|
await expect(`list.splice [1 2 3 4 5] 1 2`).toEvaluateTo([2, 3], globals)
|
||||||
|
})
|
||||||
|
|
||||||
|
test('list.splice from start', async () => {
|
||||||
|
await expect(`list.splice [1 2 3 4 5] 0 2`).toEvaluateTo([1, 2], globals)
|
||||||
|
})
|
||||||
|
|
||||||
|
test('list.splice to end', async () => {
|
||||||
|
await expect(`arr = [1 2 3 4 5]; list.splice arr 3 2; arr`).toEvaluateTo([1, 2, 3], globals)
|
||||||
|
})
|
||||||
|
|
||||||
|
test('list.sort with no callback sorts ascending', async () => {
|
||||||
|
await expect(`list.sort [3 1 4 1 5] null`).toEvaluateTo([1, 1, 3, 4, 5], globals)
|
||||||
|
})
|
||||||
|
|
||||||
|
test('list.sort with callback sorts using comparator', async () => {
|
||||||
|
await expect(`
|
||||||
|
desc = do a b:
|
||||||
|
b - a
|
||||||
|
end
|
||||||
|
list.sort [3 1 4 1 5] desc
|
||||||
|
`).toEvaluateTo([5, 4, 3, 1, 1], globals)
|
||||||
|
})
|
||||||
|
|
||||||
|
test('list.sort with callback for strings by length', async () => {
|
||||||
|
await expect(`
|
||||||
|
by-length = do a b:
|
||||||
|
(length a) - (length b)
|
||||||
|
end
|
||||||
|
list.sort ['cat' 'a' 'dog' 'elephant'] by-length
|
||||||
|
`).toEvaluateTo(['a', 'cat', 'dog', 'elephant'], globals)
|
||||||
|
})
|
||||||
|
|
||||||
test('list.any? checks if any element matches', async () => {
|
test('list.any? checks if any element matches', async () => {
|
||||||
await expect(`
|
await expect(`
|
||||||
gt-three = do x: x > 3 end
|
gt-three = do x: x > 3 end
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user