8 ms·
> I doubt that K can reduce line count by a factor 1000 though. It adds up! Consider something like this: (defun count (list) (let ((hash (make-hash
by geocar 7y ago
> I doubt that K can reduce line count by a factor 1000 though.
It adds up! Consider something like this:
(defun count (list)
(let ((hash (make-hash-table)))
(dolist (el list)
(incf (gethash (cadr el) hash 0) (car el)))
(let (result)
(maphash (lambda (key val)
(push (list val key) result))
hash)
result)))
That's just #:'=:
- Veedrac 7y agoPython 3.7+: Counter(elems).values() But we can play this game both ways. What's the K for (Counter(a) & Counter(b)).most_common(3)?
- geocar 7y agoIt's a little funny comparing a language with another language+plus-its-entire-ecosystem, but k fares remarkably well I think. Counter could be #:'=: (count each group) c:#:'=: Values would just be dot. Counter[x]&Counter[y] is a bit tricky to write, because while the documentation says set intersection, what they really mean is the set intersection of the keys with the lower of the values. This is entirely clear in k; First, understand I have a common "inter" function that I use frequently (it's actually called "inter" in q): n:{x@&x in y} and from there, I can implement this weird function with this: i:{(?,/n[!x;!y])#x&y} I've never needed this particular function, but I can read out the characters: distinct raze intersection of keys-of-x and keys-of-y, taking [from] x and y. It sounds very similar to definition of the function I gave above (if you realise the relationship between "and" and "lower of the values"), and this was painless to write. most_common could be: {k!x k:y#>x} but if I'm going to want the sort (in q) I might write y#desc x which is shorter. In this I can save a character by reversing the arguments: m:{k!y k:x#>y} so our finished program (once we've defined all our "helper functions" in a module) is: m[3] i . c'(x;y) So we're looking at 13 lexemes, versus 19 - a minor victory unless you count the cost of: from collections import Counter and start counting by bytes! But there's more value here: All of these functions operate on data, so whether the data lives on the disk or not makes no difference to k. That's really powerful. In Python I need more code to get it off the disk if that's where it is. I also may have to deal with the possibility the data might "live" in another object (like numpy) so either I trust in the (in)efficiency of the numpy-to-list conversion, or I might have to do something else (in which case really understanding how Counter[a]&Counter[b] works will be important!). I might also struggle to make this work on a big data set in python, but k will do just fine even if you give it millions of values to eat. These things are valuable. Now if you're interested in playing games, let's try something hard: "j"$`:x?`f It creates (if necessary) a new enumeration in a file called "x" which persists the unique index of f, so: q)"j"$`:x?`f 0 q)"j"$`:x?`g 1 q)"j"$`:x?`h 2 q)"j"$`:x?`f 0 How would you do this in Python?
- Veedrac 7y ago> It's a little funny comparing a language with another language+plus-its-entire-ecosystem This is pretty much my point: any ‘reimplement this weird built-in thing in $OTHER_LANG’ is going to involve overheads unless $OTHER_LANG also has that thing. I don't think keeping most types out of prelude should be a downside; you can always ‘from myprelude import * ’ if you disagree. > How would you do this in Python? I don't really know what "persists the unique index of f" means, but this seems similar to shelve. I can misuse that to give the same effect as what you showed. with shelve.open('x') as db: db.setdefault("f", len(db)) >>> 0 with shelve.open('x') as db: db.setdefault("g", len(db)) >>> 1 with shelve.open('x') as db: db.setdefault("h", len(db)) >>> 2 with shelve.open('x') as db: db.setdefault("f", len(db)) >>> 0
- geocar 7y ago> I don't think keeping most types out of prelude should be a downside I don't understand what that means. > I don't really know what "persists the unique index of f" means, but this seems similar to shelve. I can misuse that to give the same effect as what you showed. I think you got it, but it seems like a lot of typing! How many characters do you have to change if you want it purely in memory? In k I just write: `x?`f
- Veedrac 7y ago‘Prelude’ is the set of standard functions and types that you don't have to import to use. Python comes with a rich standard library, but most require imports to use. > How many characters do you have to change if you want it purely in memory? When the question is if ‘K can reduce line count by a factor 1000’, shorter keywords hardly cut it. ‘setdefault’ is wordier than ‘?’, but as something you're only going to use on occasion, so what? And d.setdefault(_, len(d)) is something you'll use maybe once a year. shelve acts like a dict, so you can do the setdefault dance the same way on in-memory dicts.
- geocar 7y ago> ‘Prelude’ is the set of standard functions and types that you don't have to import to use. Python comes with a rich standard library, but most require imports to use. I might not understand this about python. $ python3 Python 3.7.6 (default, Dec 30 2019, 19:38:26) [Clang 11.0.0 (clang-1100.0.33.16)] on darwin Type "help", "copyright", "credits" or "license" for more information. >>> Counter Traceback (most recent call last): File "<stdin>", line 1, in <module> NameError: name 'Counter' is not defined Should that have worked? Is there something wrong with my Python installation? > but as something you're only going to use on occasion, so what? And d.setdefault(_, len(d)) is something you'll use maybe once a year. If it takes that many keystrokes, you're definitely only going to use it once per year! This is the normal way you make enumerations in q/k. The low number of source-code bytes is the major feature in k. I've written some on why this is valuable, but at the end of the day, I don't really have anything more compelling than try it you might like it, and it works for me. This is something I'm working on though. - https://news.ycombinator.com/item?id=8476113 https://news.ycombinator.com/item?id=8476113 - https://news.ycombinator.com/item?id=10876975 https://news.ycombinator.com/item?id=10876975
- vatine 7y agoOTOH, a more idiomatic version would be (and I would consider using the loop facility to be idiomatic): (defun count (pair-list) (let ((hash (make-hash-table))) (loop for (val key) in pair-list do (incf (gethash key hash 0) val)) (loop for key being the hash-key of hash collect (list (gethash key hash) key)))) This drops us from 10 to 7 lines, which is clearly shorter. But, it's also relatively simple to change it from summing a list of (<count> <key>) to a list of (<key> <count>), something that I genuinely can't comment on for the K version. I suspect it would be as simple as first doing a permutation on the input, and (if needed) un-permute the result.