9
$\begingroup$

Take the following example Dataset:

data = Table[Association["a" -> i, "b" -> i^2, "c" -> i^3], {i, 4}] // Dataset

Mathematica graphics

Picking out two of the three columns is done this way:

data[All, {"a", "b"}]

Mathematica graphics

Now instead of just returning the "a" and "b" columns I want to map the functions f and h to their elements, respectively, and still drop "c". Based on the previous result and the documentation of Dataset I hoped the following would do that:

data[All, {"a" -> f, "b" -> h}]

Mathematica graphics

As you can see, the behavior is not like the one before. Although the functions are mapped as desired, the unmentioned column "c" still remains in the data.

Do I really need one of the following (clumsy looking) alternatives

data[All, {"a" -> f, "b" -> h}][All, {"a", "b"}]
data[Query[All, {"a", "b"}], {"a" -> f, "b" -> h}]
Query[All, {"a", "b"}]@data[All, {"a" -> f, "b" -> h}]

to get:

Mathematica graphics

or is there a more elegant solution?

$\endgroup$
  • $\begingroup$ maybe KeyDrop[data[All, {"a"->f,"b"->h}],"c"]? $\endgroup$ – kglr Nov 21 '16 at 23:13
  • 1
    $\begingroup$ @kglr I'd say that fits in the "inelegant" category of which I gave three examples above. Don't you think so as well? $\endgroup$ – Sjoerd C. de Vries Nov 21 '16 at 23:17
  • $\begingroup$ Sjoerd, i agree completely. $\endgroup$ – kglr Nov 21 '16 at 23:23
  • $\begingroup$ How about increasing kglr 's solution-elegance with $\endgroup$ – Mike Colacino Nov 22 '16 at 5:07
8
$\begingroup$

The following expression might not qualify as elegant, but perhaps it can be scored as less clumsy?

data[All, <| "a" -> "a" /* f, "b" -> "b" /* h |>]

dataset screenshot

| improve this answer | |
$\endgroup$
  • 1
    $\begingroup$ I like this solution. What I found inelegant in the other solutions is that you (seem to) drag around information (c in this case) that you don't need and that you throw away at the end. This feels inefficient. What if c contains a stack of MRI slices? You want to get rid of c as early in the process as possible and your approach seems to do that, at least to the eye. Whether this is actually more efficient would critically depend on the internal implementation of the process. Is it only pointers? Are actual copies of c made? Is an optimized execution plan generated that drops c at the start? $\endgroup$ – Sjoerd C. de Vries Nov 22 '16 at 6:38
  • 2
    $\begingroup$ Implementation efficiency is a slippery thing in WL, especially if we take both speed and memory into account. Empirically, I have found that in WL the fastest execution plans often (somewhat counter-intuitively) involve lots of copying. Associations (hash tries) are fairly well-behaved when it comes to copying so carrying around extra information is not necessarily harmful. My advice when it comes to performance is to benchmark using real data. In this particular case, using V11.0.1, the exhibited query resolves to a doubly-nested Map that processes the data in one pass. $\endgroup$ – WReach Nov 22 '16 at 16:38
2
$\begingroup$

I don't find @kglr solution inelegant, but perhaps a little prettier with

data[All, {"a" -> f, "b" -> h}] // KeyDrop["c"]
| improve this answer | |
$\endgroup$
  • $\begingroup$ Thanks, but see the comment below WReach's answer about why I don't like my own solutions and this one. $\endgroup$ – Sjoerd C. de Vries Nov 22 '16 at 6:35
1
$\begingroup$

Since nobody mentioned it, I will give a version with KeyTake

data[All /* KeyTake[{"a", "b"}], {"a" -> f, "b" -> h}]

Of course we can also do

data[All /* Map[Take[#, 2] &], {"a" -> f, "b" -> h}]
| improve this answer | |
$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.