ID:2125668
 
Applies to:DM Language
Status: Open

Issue hasn't been assigned a status value.
The ability to get a list of all the keys in an associative list, and all it's values, eg:
var/list/assoc_list = list("A" = 1, "B" = 2, "C" = 3)
var/list/keys = assoc_list.keys //list("A", "B", "C")
var/list/values = assoc_list.values //list(1, 2, 3)

This can be softcoded, but it's not exactly optimal.
These vars would produce lists that contain these values, rather than the actual containers themselves (the red-black tree for example)
I imagine these lists would be empty if the accessed list wasn't associative.
I came across the idea when I considered how much easier certain things would be if you could "split" an associative list like this (like looping through assoc lists just for their values)
I agree wholeheartedly with this feature request.

I am under no pressure or threat of bodily harm to show support for this feature request

The keys list is probably pointless, since just accessing the list itself would be the same thing provided there were no duplicates. Still, for completeness it would make sense if there were a values list.
In response to Lummox JR
I'm amazed at my own stupidity there, especially since to come up with this feature request I was already looping through an assoc list to get keys, and yet, never considered it pointless to have a keys list.

Yeah the values list is primarily what I'm wanting.
Thanks for taking a look at this Lum.
I can see some uses of a key list, such as if it's gonna be passed to some generic system that normally treats associated values specially, and you don't want to make a new version of that system or add in a new arg just for one special snowflake case.
AFAIK there's no way to differentiate between an assoc list and a normal list so something like this or a var would be great.
In response to Somepotato
If you use json_encode(List), the result will start with a "[" for a non-associative list, and "{" for an associative list.

Interestingly, setting a key to null still makes it convert into an JSON object instead of an array.
That's a horrifying solution :o
In response to Somepotato
I know, but I brought it up more because it shows that there might be a difference internally that json_encode() takes advantage of.
Also for instance it throws an exception if you try to read a non-existent key from a non-associative list iirc.
In response to Somepotato
Is that a suggestion?

Currently, if you try to read a non-existent key, regardless of whether the list is an array or a dictionary, you get null. (unless the key is a number, in which case you could get an index out of bounds error)

I don't think that anything built-in throws any actual exceptions (yet), unless you count all runtime errors.
Must be mistaken then
You're correct; json_encode() looks for whether the list has an attached tree.
Any chance we can get this for 512?
In response to CrimsonVision
CrimsonVision wrote:
Any chance we can get this for 512?

Yes. I'll put this on my list for consideration.
Excellent.
In response to Somepotato
Somepotato wrote:
AFAIK there's no way to differentiate between an assoc list and a normal list so something like this or a var would be great.

Build in function for this will be useful. But now, if anyone is interested, after some experiments I come to this variant

/proc/is_associative(list/L)
var/index = 0
for(var/key in L)
index++

var/value = null
// if key not num we can check L[key] without fear of "out of bound"
// else compare to index to prevent runtime error in e.g. list(5, 1)
// L[key] will exist and be same as key if we iterating through not associative list e.g. list(1, 2, 3)
if(!isnum(key) || (!(isnum(key) && index != key) && L[key] != key))
value = L[key]

if(!isnull(value))
return TRUE

return FALSE


Just one problem: list("one": null, "two": null) will be parsed as not associative, the solution is to use list("one": 0, "two": 0)

bump
You can also use the fact that json_encode knows whether a list is associative or not. Maybe not the fastest method:
proc
is_associative(list/L)
return "{" == copytext(json_encode(L), 1, 2)
What's interesting is I had to make an altered version of params2list() for greater compatibility with json_encode():
proc/params2listStrict(params)
/*
Works the same as params2list() if an equals sign is found. Otherwise, a non-associative list is returned.

Ultimately, the difference is subtle, but can be detected by procs like json_encode(),
which can mean the difference between returning a string with an array or an object.
*/

if(findtext(params, "="))
. = params2list(params)
else
params = params2list(params)
. = list()
for(var/p in params)
. += p

This is required for my implementation of cross-language argument passing, which is starting to look so much like a REPL (Read-Eval-Print-Loop) that it's scary. Whenever languages interact, they tend to unintentionally create a new language. If you start to see emergent behavior in your program, it usually means that some aspect of Lisp is haunting your code.