9 ms·
Zip Function Solution: Haskell, Elixir, JavaScript, Python, Vlang
- rmetzler 4y agoI‘m not good in JavaScript, but reading the code, I wonder if this implementation doesn’t have an issue with truthiness in the second array. For example if you zip([true,true],[false,false]). The minimum length approach seams to be the better one. (Without having it run anywhere.)
- universa1 4y agoThat was my quick reaction as well... I think it would need something like the python example below, where you first check the lengths of the two arrays/lists, and then iterate over that, and not directly over the length of the first list. iter_limit = Math.min(ls1.length, ls2.length); for(let i = 0; i < iter_limit; i++)...
- chrisco255 4y agofunction zip(arr_a, arr_b) { const len = arr_a.length < arr_b.length ? arr_a.length : arr_b.length; return arr_a.slice(0, len).map((el, idx) => [el, arr_b[idx]]); }
- m-r-r 4y agoYes, the JavaScript implementation doesn't works if the second array contains 'false', 'null', 'undefined', '0' or 'NaN'. Here is my implementation of the 'zip' function in modern JavaScript. It is similar to the Vlang version, but it is generic over the number of arrays : const zip = (...arrays) => { const length = Math.min(...arrays.map((array) => array.length)); return Array.from({ length }, (_, i) => arrays.map((array) => array[i])); };
- asplake 4y agoFor Python, I’d prefer a generator over appending. Less imperative style-wise and faster too I think.
- BiteCode_dev 4y agoIt's a good learning exercise. Of course, don't use your own hand crafted version in Python, since one is provided with the language and it is better than the one you will likely come up with. Still, it's interesting because it's simple. So starting from the intro of this article, if you want to go further, try to do the following to match up __builtins__.zip: - make it lazy (yield would work) - make it work with any iterable (iter() + StopIteration would work) - put some type int and a docstring (so that help() gives you informations) - accept any number of iterables (variadic parameters would work) - make a second version that accepts a fill value (like itertools.zip_longest) This will sharpen your python skills, and also will make you appreciate even better how much you get for free with the stdlib (not to mention __builtins__.zip is in C, so it's fast).
- qsort 4y ago> will make you appreciate even better how much you get for free This is unironically the reason I come back to Python again and again. The language itself is not my favorite: it 'should' be different. But my productivity with it is frankly unmatched. The "zip" example is an excellent case study. The actual "zip" is by default lazy, it accepts arbitrary iterators, etc. It's the "correct" solution, unlike the one presented in the article, and I have it at my fingertips, in the standard library.
- canadianfella 4y ago> This is unironically the reason Can I ask an off topic question? Where did this sudden popular use of “unironically” come from? I don’t get it. Why would it be ironic? It reminds me of the sudden rise of “literally” a decade or so ago.
- Joker_vD 4y ago"Unironically" here means "seriously", "literally", "actually", etc. It's basically a marker that the speaker is speaking straightly and plainly, without trying to make a joke. Yes, it's not really antonymous to "ironically" (in the narrower sense of this word) in this context.
- jphoward 4y agoGenerally in Python it's much better to use list comprehensions when possible, it offers significant speedups usually: def zip(ls1, ls2): return [(ls1[i], ls2[i]) for i in range(min(len(ls1), len(ls2)))] And indeed you could even use a generator instead: def zip(ls1, ls2): return ((ls1[i], ls2[i]) for i in range(min(len(ls1), len(ls2))))
- phoe-krk 4y agoCommon Lisp version, works with an arbitrary number of lists and automatically trims the result to the length of the shortest list. (defun zip (&rest lists) (apply #'mapcar #'list lists)) Example: CL-USER> (zip '(1 2 3) '(4 5 6 7 8) '(a b c d)) ((1 4 A) (2 5 B) (3 6 C))
- lispm 4y agoLimited by the implementation specific max number of arguments.
- PufPufPuf 4y agoThe inclusion of Vlang is interesting. I remember that it was created together with Volt, a multi-service messenger app that never delivered. Is the language any good, and are there any advantages over more established esoteric systems languages like D, Nim, or Zig?
- jonathanstrange 4y agoFrom a pure language perspective, not taking into account infrastructure and implementation, Vlang is currently my favorite language. It has pretty much the syntax and semantics I want in a statically compiled, strongly typed language. However, there are still too many features of the current implementations that are in reality not yet implemented or too experimental. It's still not ready for production and larger projects. I'd say the languages you mention are substitutes according to the following mapping: C++ => D Python => Nim C => Zig Go => V
- rmanolis 4y agoV promised a lot of stuff as ready but has undelivered most of them and people lost trust. If V was truthful like Zig, it would be able to create a foundation. Also a programming language will never be able to substitute another one if it is not able to call its vast number of libraries.
- jonathanstrange 4y agoI agree, the table refers to the intention of the language developers and how the languages feel, it's not about real substitution. For example, D was explicitly designed as a better version of C++ and also allows you to use C++ libraries directly, and Zig is explicitly intended as a modern substitute for C. As for V, it delivers quite well for a language at such an early stage and has a growing community. IMHO, it's a great language.
- Strum355 4y agoStill would not use V myself, its the prime example of overmarketing of impossible features, silencing of critics online etc
- Ndymium 4y agoInterestingly, the post says "JavaScript [...] has tail call issues", but at least the Elixir algorithm is not tail recursive and will blow up with inputs that are too big.
- sph 4y agoMake it simple, THEN make it fast/efficient. Here's a tail-recursive function. To be honest I would have started writing this version first, the acc pattern is ubiquitous. Sorry for the mistakes, I'm on mobile: def zip(a, b) do zip(a, b, []) end def zip([], _, acc), do: acc def zip(_, [], acc), do: acc def zip([a | a_rest], [b | b_rest], acc) do zip(a_rest, b_rest, [{a,b}|acc]) end Also, there's Enum.zip/2 in the standard library, with the bonus that it works with any Enumerable type (lists, maps, lazy streams, etc,)
- Ndymium 4y agoSure, but if we want to highlight other languages' lack of tail call support, maybe we should showcase that support in those languages that do support it. :)
- karmakaze 4y agoThe JavaScript one is incorrect. It should use the length of the 2nd list rather than stop at the first falsy value in it. That's where I stopped reading. Even going in, I wondered doesn't each of these languages already have a function in stdlib or a de-facto package with it?
- krab 4y agoA simpler (IMHO) Python version, plus lazy and working on any iterable. Also, it's quite easy to adapt it to work on any number of iterables. def myzip(x, y): x, y = iter(x), iter(y) try: while True: yield next(x), next(y) except StopIteration: return
- greenpeas 4y agoI was looking for a way to implement this more pythonically. And this looks great. But it made me think that if x and y are of different lengths, the last iteration might consume an element out of the longer iterator. So I tried it with the builtin `zip(a,b)`, and indeed, if a is shorter, `zip(a,b)` consumes the same number of elements from both a and b. But if a is longer, then `zip(a,b)` consumes one extra element from a. I don't know if this behavior is well defined, that is whether I can rely on this, or the order of evaluation of the arguments of a function is up to the interpreter/compiler, and may change. masklinn wrote a comment in another thread about this that i didn't understand until I saw your implementation.
- Joker_vD 4y agodef myzip(*seqs): next_yield = [None] * len(seqs) its = [iter(seq) for seq in seqs] should_go = True while should_go: for index, it in enumerate(its): try: next_yield[index] = next(it) except StopIteration: should_go = False if should_go: yield tuple(next_yield) It consumes exactly the same number of elements from all sequences, unless a non-StopIteration exception occurs during the iteration.
- leprechaun1066 4y agoq: {(,')over min[count each x]#'x} k4: {,'/(&/#:'x)#'x}
- chrisco255 4y agoMy solution for Javascript: function zip(arr_a, arr_b) { const len = arr_a.length < arr_b.length ? arr_a.length : arr_b.length; return arr_a.slice(0, len).map((el, idx) => [el, arr_b[idx]]); }
- deleted 4y ago[deleted]
- bloaf 4y agoIn TCL, zip functionality is built into the foreach loop. foreach x $list1 y $list2 { lappend result [Myfunc $x $y] } To directly return a list of outputs without having to append to a list, TCL also provides lmap which works the same way: lmap x $list1 y $list2 {Myfunc $x $y} But wait there's more! Foreach and lmap also support taking more than one element from the list each time: lmap {x y} $list1 {Myfunc $x $y}
- lupire 4y agoIt's gauche to flaunt the power of the gods among mortals.
- deleted 4y ago[deleted]
- deleted 4y ago[deleted]
- frankenst1 4y agoIn JavaScript: let zip = (as,bs) => as.slice(0, Math.min(as.length,bs.length)).map((a,i) => [a,bs[i]]);
- tmtvl 4y agoFP is nice, but logic programming also has its niceties. (define (zipo a b z) (conde ((nullo a) (nullo z)) ((nullo b) (pairo a) (nullo z)) ((fresh (ahead atail bhead btail ztail) (conso ahead atail a) (conso bhead btail b) (conso (list ahead bhead) ztail z) (zipo atail btail ztail))))) (run* (q) (zipo '(1 2 3) '(a b c) q)) => (((1 a) (2 b) (3 c))) (run* (q) (zipo '(1 2 3) q '((1 a) (2 b) (3 c))) => ((a b c . _.0))
- kazinator 4y agozip is useful to have as a library function in a Lisp dialect in spite of being easily able to compose it with mapcar and list. It comes up fairly often in macros. E.g. you have gens, a list of gensyms, and exprs, a list of expressions, and body, a list of forms that refer to the gensyms: `(let ,(zip gens exprs) ,@body)