In K, most of these are are a single built-in operation or simple composition:
|: / reverse a string/list
~2! / is a number even? (works on nested structures, too)
?, / intersection of two lists
?: / remove duplicates from a list
#: / string/list length (normal)
+/~0= / string/list length (avoid using 'count')
{&/|/x=/:y} / does y contain all elements of x?
10?"a" / 10 random letters (a special case of 'draw')
10/ / turn a list of digits into a base-10 number
{x~|x} / is a string/list a palindrome?
,/ / flatten a list (one level)
,// / flatten a list (recursively)
*<#:'=: / find the most frequent element of a list
, / a 'list join' is also a dictionary union
K is a curious language in the APL family created by Arthur Whitney. One of its primary features is conciseness (which makes it look like line noise), to be able to see as much of an entire program as possible at a time. The latest version I know of is Shakti, also known as k9. Open source implementations I’m aware of include ngn/k, oK, and kona, though they all implement different versions/variations of the language.
There aren’t many symbols to remember; K only uses standard ASCII. An expert will have most or all of the vocabulary memorized in the same sense that most programmers don’t need Google to look up the symbol for performing addition in their language of choice.
For beginners (or anyone acclimating to an unfamiliar dialect), K interpreters typically include a built-in reference card. More comprehensive reference manuals are available for oK and K2.
I don’t get the point of this article. None of these is a lifesaver, and you learn all of this early on in your learning of the language. This article could make sense as an advocacy piece of a kind “look at these cool things you can do in this language,” but Python is already ubiquitous these days, so it is difficult to imagine someone who would be interested in what Python has to offer but just didn’t happen to notice this tiny obscure language just yet…
I’ve had a lot of colleagues that would write a for loop for most of those idioms, resulting code both slower and less concise.
That said, the list could have used the standard library more, and avoided mistakes such as the quadratic contains_all.
every day somebody is born who doesn’t know about my_list[::-1]!
In the abstract, writing out things more clearly is Better(TM). But if you’re really verbose about certain things, then suddenly your function that could have been 4 lines is now 12 lines, or it could have been 10 and is now 25… and at one point length becomes a legibility concern!
I don’t necessarily “agree” with a all the listed one-liners, but there is value in context to terser code, especially if it’s idiomatic (-> easier to read for other pythonistas). If only because terse code + a comment might be even clearer than a more verbose approach (that might be hiding bugs).
Since a list can contain duplicate elements, should the intersection of 2 lists have the duplicates as well?
I think this depend on the actual definition of the intersection, IIRC it is:
for all x in a, x in “a&b” <=> x in b
This would mean that for:
a = [1, 2, 2, 3]
b = [2, 3, 4]
a&b should be [2, 2, 3] : 1 is not in b, 2 is in b, 2 is in b, 3 is in b. Note how it does not include the 2 and 3 that are in b.
The “remove duplicates from a list” example does not preserve order. I can’t think of a one-liner that does, since you need some kind of stateful iteration to keep track of unique elements and that probably warrants multiple lines.
in older 3.x releases you could explicitly use an OrderedDict. And the restriction to hashable elements also applies to the set-based implementation from the article I think?
If you wanted to avoid that, you could do something hacky with reduce or a list comprehension, but it’d be inefficient due to having to do all the membership tests in lists.
Since Python 3.9 you can merge two dicts with
dict1 | dict2
In K, most of these are are a single built-in operation or simple composition:
Today I learned about this
Out of curiosity what’s K
K is a curious language in the APL family created by Arthur Whitney. One of its primary features is conciseness (which makes it look like line noise), to be able to see as much of an entire program as possible at a time. The latest version I know of is Shakti, also known as k9. Open source implementations I’m aware of include ngn/k, oK, and kona, though they all implement different versions/variations of the language.
How do you search google for the meaning of these symbols? Google loves to strip out non-alphanumeric.
There aren’t many symbols to remember; K only uses standard ASCII. An expert will have most or all of the vocabulary memorized in the same sense that most programmers don’t need Google to look up the symbol for performing addition in their language of choice.
For beginners (or anyone acclimating to an unfamiliar dialect), K interpreters typically include a built-in reference card. More comprehensive reference manuals are available for oK and K2.
The same, but in Ruby:
Reverse a String: Check if a Number is Even: Find the Intersection of Two Lists: Remove Duplicates from a List: Calculate the Length of a String without Using .length/.size/.count: Check if a List Contains All Elements of Another List: Generate a String of Random Characters: Convert a List of Integers to a Single Number: Palindromic Check: List Flattening: Find the Most Frequent Element in a List: Merge Two hashes:That’s pretty interesting,
Ruby has been on my list for a long time and I have been really amazed by the simplicity of Ruby and RoR web framework
And thanks for sharing this
I don’t get the point of this article. None of these is a lifesaver, and you learn all of this early on in your learning of the language. This article could make sense as an advocacy piece of a kind “look at these cool things you can do in this language,” but Python is already ubiquitous these days, so it is difficult to imagine someone who would be interested in what Python has to offer but just didn’t happen to notice this tiny obscure language just yet…
I think that sums it up. There’s always something new to learn.
I’m not a Python developer, so I found the article very interesting, even though (in my very biased opinion), Ruby does it much better.
I work with data scientists who write Python and they learn little things like this all the time.
For notes on the article:
reversed(string)
when you don’t have an idea of the length, then"".join(reversed_string)
later.def
, Guido’s orders.def is_even(x: int): return x % 2
len()
is normal and I think the length of a string is stored alongside the string in memoryset(a) ^ set(b)
should be an empty set. (I think that’s what’s being achieved here.)I’ve had a lot of colleagues that would write a for loop for most of those idioms, resulting code both slower and less concise. That said, the list could have used the standard library more, and avoided mistakes such as the quadratic
contains_all
.every day somebody is born who doesn’t know about
my_list[::-1]
!In the abstract, writing out things more clearly is Better(TM). But if you’re really verbose about certain things, then suddenly your function that could have been 4 lines is now 12 lines, or it could have been 10 and is now 25… and at one point length becomes a legibility concern!
I don’t necessarily “agree” with a all the listed one-liners, but there is value in context to terser code, especially if it’s idiomatic (-> easier to read for other pythonistas). If only because terse code + a comment might be even clearer than a more verbose approach (that might be hiding bugs).
It may be useful to note that the list flattening is not recursive (unlike the ruby answer), only one level is flattened:
If you’re okay with cheating and
eval
, there is a one-liner for recursive flattening:Otherwise, a recursive function is decently short:
If you have deeply nested lists, I suppose you may want something like this:
Most frequent can be done with
collections.Counter
List flattening can be done with
itertools.chain
:The
string
module comes with constant containing all ascii letters for convenience:Contains all as implemented is quadratic. Best to convert
list1
to a set first:I tried to recreate this with Haskell “one-liners”:
And in oK:
the most frequent trick
is “accidentally quadratic”, because
my_list.count
is a linear search and you’re doing it once for each distinct item.better to use
collections.Counter
Since a list can contain duplicate elements, should the intersection of 2 lists have the duplicates as well? I think this depend on the actual definition of the intersection, IIRC it is:
This would mean that for:
a&b
should be[2, 2, 3]
: 1 is not in b, 2 is in b, 2 is in b, 3 is in b. Note how it does not include the 2 and 3 that are in b.Am I mistaken?
[Comment removed by author]
Mathematically, intersection means the things that are in both lists. So I’d expect the output to contain two
2
s only if both input lists do.next(g.gi_frame for _ in [1])
It’s a fun one for candidate interviews “explain what happens here”
Can anyone try this using lisp
Are similar one-liners not possible in every well-used scripting language?
The “remove duplicates from a list” example does not preserve order. I can’t think of a one-liner that does, since you need some kind of stateful iteration to keep track of unique elements and that probably warrants multiple lines.
This is because since Python 3.7,
dict
is insertion-ordered, sodict.fromkeys()
preserves the ordering. It’s slower though.EDIT: Also, note that it does not work with non-hashable items
EDIT2: https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.unique_everseen
in older 3.x releases you could explicitly use an OrderedDict. And the restriction to hashable elements also applies to the set-based implementation from the article I think?
If you wanted to avoid that, you could do something hacky with
reduce
or a list comprehension, but it’d be inefficient due to having to do all the membership tests in lists.Nice! The set solution won’t work with non-hashable types anyway, right?