funkia / list Goto Github PK
View Code? Open in Web Editor NEWπ An immutable list with unmatched performance and a comprehensive functional API.
License: MIT License
π An immutable list with unmatched performance and a comprehensive functional API.
License: MIT License
Hi paldepind, thanks for making this interesting library.
I wonder why you chose to make functions as stand-alone and not property methods on the List class? This would make them a little more convenient to use, i.e. xs.filter(p)
instead of L.filter(xs, p)
.
/Dan
I used funkia/list on a larger project and was generally very happy with it. One big missing piece for me was the availability of a NonEmptyList. Having this available helps reduce a lot of code concerned with checking if a list is empty or not, because in many situations an empty list would be an application error and should be caught far out in the API layer, not in the app's core code.
The fp-ts NonEmptyArray is a good starting point for how this should work.
I think you have exchange row 18 with 19 in:
make-proxies
so there is a comma problem in package.json
I have a strange warning too
WARNING in ./node_modules/list/dist/es/index.js
(Emitted value instead of an instance of Error) Cannot find source file '../../src/index.ts': Error:
Can't resolve '../../src/index.ts' in '/functionalHyperscriptTodoList/node_modules/list/dist/es'
regards
such code:
// do a cheap slice by setting prefix length
bits = setPrefix(prefixSize - from, bits);
is not quite OK. list should wipe pointers to the items to enable them to be garbage collected, otherwise we have in effect a memory leak.. Items are unreachable for list users but list holds them in memory.
Hi,
First, great lib π
I wanted to know if you were planning on adding a method allowing to sort on multiple fields?
I played with your codebase, and I implemented (naΓ―vely) it like this:
type SortOption<T> = {
by: (item: T) => string | number
reverse?: boolean
}
function sortByMultipleFields(opts: SortOption<T>[], l: List): List {
if (l.length === 0) {
return l;
}
let arr = l;
arr = [].concat(l.prefix, l.suffix) // quick and dirty...
arr.sort((a, b) => {
for (let index = 0; index < opts.length; index++) {
const { by, reverse = false } = opts[index];
if (by(a) < by(b)) return reverse ? 1 : -1;
if (by(a) > by(b)) return reverse ? -1 : 1;
}
return 0;
});
let newL = emptyPushable();
for (let i = 0; i < arr.length; ++i) {
push(arr[i], newL);
}
return newL;
}
exports.sortByMultipleFields = sortByMultipleFields;
Then, you can use it like this:
const items = L.list(
{ id: 2, name: 'bb' },
{ id: 1, name: 'bb' },
{ id: 2, name: 'aa' },
{ id: 1, name: 'aa' }
)
const sortedItems = items.sortByMultipleFields([
{ by: i => i.id }, // first I want the items sorted by their id
{ by: i => i.name, reverse: true }, // then, by their name, but in reverse order
])
// sortedItems = [
// { id: 1, name: 'bb },
// { id: 1, name: 'aa },
// { id: 2, name: 'bb },
// { id: 2, name: 'aa' },
// ]
The link: http://vindum.io/blog/how-can-list-be-faster-than-native-arrays/
git blame: 1a102ca
see also: paldepind/paldepind.github.io#1
It would be nice if this blog post were hosted somewhere else, preferably somewhere safe.
I suggest putting it up as a https://dev.to/ blog post.
in the splitAt
part you have named the example takeLast
I got this stack when playing with list in my fuzzer (2.0.14) =>
TypeError: Cannot read property 'sizes' of undefined
at sliceRight (node_modules/list/dist/index.js:1220:49)
at sliceRight (node_modules/list/dist/index.js:1227:21)
at slice (node_modules/list/dist/index.js:1347:28)
at Object.take (node_modules/list/dist/index.js:1360:12)
at Vector.take (dist/src/Vector.js:613:29)
at Array.<anonymous> (dist/tests/Seq.js:362:62)
at Context.<anonymous> (dist/tests/Seq.js:384:28)
presumably that should never happen. I have no reproduction for now.
I am looking for R.reduced
to prevent excessive reducing. Any plans for it?
I know it is a stupid question, but
import * as L from "list";
not work.
I am using typescript 2.7.2 and this is a package.json bit:
"engines": {
"node": "9.11.1"
},
"dependencies": {
"@types/ramda": "^0.25.0",
"classnames": "^2.2.5",
"hyperscript": "^2.0.2",
"hyperscript-helpers": "^3.0.3",
"inferno": "^5.0.1",
"inferno-hyperscript": "^5.0.1",
"inferno-redux": "^5.0.1",
"list": "^2.0.7",
"ramda": "^0.25.0",
"redux": "^3.7.2",
"reselect": "^3.0.1",
"type-to-reducer": "^1.1.0"
},
"devDependencies": {
"@types/classnames": "^2.2.3",
"awesome-typescript-loader": "^4.0.1",
"clean-webpack-plugin": "^0.1.17",
"css-loader": "^0.28.11",
"ejs-loader": "^0.3.1",
"extract-text-webpack-plugin": "3",
"file-loader": "^1.1.11",
"html-webpack-plugin": "^3.1.0",
"source-map-loader": "^0.2.3",
"style-loader": "^0.20.3",
"typescript": "^2.7.2",
"uglifyjs-webpack-plugin": "^1.1.6",
"webpack": "3",
"webpack-bundle-analyzer": "^2.11.1",
"webpack-cli": "2",
"webpack-dev-middleware": "3",
"webpack-dev-server": "2",
"webpack-merge": "4.1.1",
"xml-loader": "^1.2.1"
}
if I try this
import { List } from "list";
not work too.
some message:
No declaration file was found for the 'list' module. A '.../functionalHyperscriptTodoList/node_modules/list/dist/index.js' is implicitly assigned an 'any' type.
Trynpm install @ types / list
if it exists or add a new declaration file with extension d.ts containingdeclare module 'list';
what is my error?
regards
so i've been a been worried because of the bug I found previously in list and decided to write a fuzzer to search for bugs. The fuzzer is relavitely easier to write for me because I have several collections with the same API (vector, linkedlist, stream).
And actually it found at least one bug in list 2.0.14. There could be several, it's hard to tell. I've extracted a reproduction from a run of the fuzzer where the reproduction was a little shorter... But obviously it's not exactly a minimal reproduction.
Here's the reproduction, I run actions on both list and a plain JS array. The actions should result in the same result, but they don't.
notice that both lists have the same value up to the last computation. So in the end to convince yourself there's a bug you only need to review the last lines.
The final lists are completely different, list
returning a list starting with [ 2704, 2688, 2672, ..
and JS arrays by [ 1136, 1128, 1120, ...
.
const L = require("list")
let f = L.list()
let g = []
function arrayOfLength(l:number) {
const r = [];
for (let i=0;i<l;i++) {
r.push(i);
}
return r;
}
f = L.map(x=>x*2, f)
g = g.map(x=>x*2)
f = L.concat(f, L.from(arrayOfLength(176)));
g = [...g,...arrayOfLength(176)];
f = L.concat(f, L.from(arrayOfLength(230)));
g = [...g,...arrayOfLength(230)];
f = L.take(24, f);
g = g.slice(0,24)
f = L.take(116, f);
g = g.slice(0,116)
f = L.concat(f, L.from(arrayOfLength(125)));
g = [...g, ...arrayOfLength(125)];
f = L.map(x=>x*2, f)
g = g.map(x=>x*2)
f = L.concat(f, L.from(arrayOfLength(192)));
g = [...g, ...arrayOfLength(192)];
f = L.concat(f, L.from(arrayOfLength(211)));
g = [...g, ...arrayOfLength(211)];
f = L.concat(L.from(arrayOfLength(243)), f);
g = [...arrayOfLength(243),...g];
f = L.map(x=>x*2, f)
g = g.map(x=>x*2)
f = L.reverse(f)
g = g.reverse()
f = L.concat(f, L.from(arrayOfLength(236)));
g = [...g, ...arrayOfLength(236)];
f = L.reverse(f)
g = g.reverse()
f = L.concat(f, L.from(arrayOfLength(231)));
g = [...g, ...arrayOfLength(231)];
f = L.map(x=>x*2, f)
g = g.map(x=>x*2)
f = L.drop(81, f)
g = g.slice(81)
f = L.map(x=>x*2, f)
g = g.map(x=>x*2)
f = L.concat(f, L.from(arrayOfLength(142)));
g = [...g, ...arrayOfLength(142)];
f = L.reverse(f)
g = g.reverse()
f = L.map(x=>x*2, f)
g = g.map(x=>x*2)
f = L.concat(f, L.from(arrayOfLength(112)));
g = [...g, ...arrayOfLength(112)];
f = L.concat(f, L.from(arrayOfLength(121)));
g = [...g, ...arrayOfLength(121)];
// up to here both lists are equal
f = L.drop(230, f)
g = g.slice(230)
console.log(L.toArray(f))
console.log(g)
Hi
My use case frequently involves mapping a list of raw data into a UI representation that offers the ability to modify elements. For instance mapping a list into table rows, where the user may modify or delete rows. I was thinking having the index available when mapping would allow me to efficiently update the list on that index.
One could use List.zipWith(f, list, List.range(0,List.length(list))) or avoid the index and use List.find but maybe there is a place for a dedicated mapWithIndex function as that should theoretically be more efficient?
Does anyone else have similar use-cases and what is your solution?
Finally, thanks for a great lib!
I tried to use groupWith
like so:
import * as L from "list/methods";
const xs = L.list({ x: 1 }, { x: 2 }, { x: 3 }, { x: 1 }, { x: 2 }, { x: 3 });
const groupedXs = xs.groupWith((a, b) => {
console.log(a.x, b.x);
return a.x === b.x;
});
I would have expected this result: list(list({x: 1}, {x: 1}), list({x: 2}, {x: 2}), list({x: 3}, {x: 3}))
.
But I just got the original list back, nested: list(list({x: 1}), list({x: 2}), list({x: 3}), list({x: 1}), list({x: 2}), list({x: 3}))
.
What's happening becomes more clear from the console.log
, which shows what's being compared:
1 2
2 3
3 1
1 2
2 3
Hi guys,
first, I just wanted to congradulate you on some very impressive work!
have you guys thought about the argument order on fold operations?
for the sake of compliance with existing JS, fantasy-land specifies the argument order for reduce
to be (accumulation, currentValue)
.
However, functional conventions is to always have the collection argument last(e.g. ramda), to encourage function composition, example:
const a = list(0,1,2,3,4,)
const b = list(5,6,7,8,9)
let ten = L.foldl(L.append, a, b) // reuse existing function
// list(0,2,3,4,5,6,7,8,9)
ten = L.reduce((items, value) => L.append(value, items), a, b); // requires an additional step
// list(0,2,3,4,5,6,7,8,9)
it makes more sense to me to keep ramda style argument ordering for foldl
/foldr
and follow fantasyland for reduce
/reduceRight
thoughts?
> var {list} = require ('list')
> var show = require ('sanctuary-show')
Current behaviour:
> show (list ('foo', 'bar', 'baz'))
'{"bits": 3, "length": 3, "offset": 0, "prefix": [0], "root": undefined, "suffix": ["foo", "bar", "baz"]}'
Suggested behaviour:
> show (list ('foo', 'bar', 'baz'))
'list ("foo", "bar", "baz")'
This would require defining a @@show
method which applies show
to each of the list's elements.
I saw on the main page list is compatible with ramda's sort function, but have run into problems converting some code to list.
const L = require('list/curried')
const R = require('ramda')
const array = [
{ id: 1 },
{ id: 3 },
{ id: 2 },
]
const list = L.fromArray(array)
// ramda sort array
R.sort((a, b) => a.id - b.id, array) //=> [ { id: 1 }, { id: 2 }, { id: 3 } ]
// ramda sort list
R.sort((a, b) => a.id - b.id, list) //=> [ , , ]
// list sort list
L.sort((a, b) => a.id - b.id, list) //=> []
I have also noticed const L = require('list/curried')
does not curry.
const sortRamdaId = R.sort((a, b) => a.id - b.id)
const sortListId = L.sort((a, b) => a.id - b.id)
sortRamdaId(array) //=> [ { id: 1 }, { id: 2 }, { id: 3 } ]
sortListId(list) //=> ERROR: sortListId is not a function
Am I using this correctly?
I can't find a way to loop over a List backwards. The only way seems to be to use reverse
, but this is very inefficient for large lists.
There is reduceRight
/foldr
, but those don't allow for early termination.
I think we need a function
function reverseIterator<A>(l: List<A>): Iterator<A>;
(Similar to C++ rbegin
/rend
)
noticed this in uses from my prelude.ts library :-(
list appears to get confused by a series of operations, let's say its internal structures get corrupted, and it returns wrong results.
I made a reproduction script:
const L = require("list")
let f = L.list()
for (let i=0;i<1329;i++) {
f = L.append(i, f);
}
const b = L.drop(L.length(L.takeWhile(l=>l<=200, f)), f)
const c = L.takeWhile(l=>l<=203, b)
const d = L.drop(L.length(c), b)
console.log("FIRST ISSUE first() doesn't agree with nth(0)")
console.log(L.first(d))
console.log(L.nth(0, d))
const c1 = L.append(L.nth(0, d), c)
console.log("SECOND ISSUE list of 4 drop first and last, wrong result")
console.log(L.toArray(c1))
console.log(L.toArray(L.dropLast(1, L.drop(1, c1))))
The output is:
FIRST ISSUE first() doesn't agree with nth(0)
201
204
SECOND ISSUE list of 4 drop first and last, wrong result
[ 201, 202, 203, 204 ]
[ 201, 202 ]
How would I go about making a .random function that would allow me to get a random value of the list? I can do it for normal arrays but I'm not sure how to do it for list.
Normal array Random code:
Array.prototype.random = function() {
return this[Math.floor(Math.random() * this.length)];
};
Hi, first thanks for your great lib which I'm happy to use in my projects. Recently ran into an issue: needed findLastIndex()
which is not implemented. If you are ok with it, I'm ready to make pull request.
The idea would be to have an operator that takes a function and a count to generate a new list.
At first, I thought that was what repeat was doing.
Example
const generateDot = () => {
const x = Math.random() * this.width;
const y = Math.random() * this.height;
return { x, y };
}
const dots = generate(generateDot, 50); // I couldn't find a name for the operator.
Im not sure about exact algo of how it works just yet, but I suspect that this field is unsafe at the moment because, while main entry has no side effects and this package.json field can be used safely for it, the other entries such as fantasy-land are actually effectful and might be dropped because of that.
I can check with webpack@4-beta later how it behaves.
You mutate arguments. That is "unfunctional and bad style".
Examples:
Lines 982 to 991 in b626bb5
This should be fixed and never be done again. Actually nothing should ever be mutated in the whole codebase of this library.
Library seems to not export nor having fromArray
function.
Specifically, I'm trying to import it as ES-module and bundled dist from npm doesn't have this function in exports.
Is it just me or head is missing in all type definitions? and code?
documentation mentions it as an alias for first?
list version 2.0.18
thanks
I find myself using npm.js to search for packages I use regularly, usually to RTFM, and was not able to find the link to this repo from https://www.npmjs.com/package/list.
L.nth(-1, L.empty()) // 0
It appears to be an off-by-one error as:
L.nth(-2, L.empty()) // undefined
The dropRepeatsWith
entry in the main readme is incorrect - https://github.com/funkia/list#droprepeats-1
It's listed as dropRepeats
(missing the With
), and the code example is shown as ropRepeatsWith
(missing the d
).
How can you use this list with Ord
?
as you know, I'm writing the prelude.ts library, and now using your list library as a backing implementation for the Vector. I'm currently considering switching the prelude's flatMap implementation away from the current prelude.ts and also the current list
behavior, I was wondering if you have a particular opinion about this behavior.
Currently list
has:
export function flatMap<A, B>(f: (a: A) => List<B>, l: List<A>): List<B>
The change I'm contemplating for prelude.ts would be:
export function flatMap<A, B>(f: (a: A) => Iterable<B>, l: List<A>): List<B>
And prelude.ts has the same (and had the same before it switched to a list
backend for the Vector). It turns out that scala, and also immutablejs are using the looser Iterable-based signature.
list
and prelude.ts however have the tighter type-signature, and for list
:
> list.toArray(list.chain(x=>list.list(1,2,3), list.list(1,2,3)))
[ 1, 2, 3, 1, 2, 3, 1, 2, 3 ]
> list.toArray(list.chain(x=>[1,2,3], list.list(1,2,3)))
[]
To be clear, I'm not asking you to modify list
to work in that different way, I'm asking if you had a reflection on that topic and decided that the current list
signature is better. For me, in prelude.ts, I was guided by the monadic bind type-signature, and it didn't occur to me to "loosen up" the type signature, which could have advantages and inconvenients, but now I started thinking about it, and I may, or may not, make that change.
Hello, I liked to know what kind of Lists you have implemented: if your List have a math name or are
inspired to a math algorithm?
regards
A declarative, efficient, and flexible JavaScript library for building user interfaces.
π Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. πππ
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google β€οΈ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.