Apply a function to each row of a Dataset

Here is a way that generates the columns in the order that they occur in the original dataset:

dsAll[
  Select[#class==="apples"&] /* KeyUnion
, <| "Name" -> #name, #name -> #value& /@ #params |>&
]

dataset screenshot

If the exact order of the columns is important, an additional re-ordering stage can be added:

dsAll[
  Select[#class==="apples"&] /* KeyUnion
, <| "Name" -> #name, #name -> #value& /@ #params |>&
][All, {"Name", "COLOR", "EXP_DATE", "TYPE", "WEIGHT"}]

dataset screenshot, columns reordered


This is quite a bit awkward, but perhaps you can use this as a starting point:

dsApples = dsAll[Select[#class === "apples" &], {"name", "params"}];

tmp = Join[dsApples[All, Key["name"] /* <|"Name" -> Identity|>], 
           Dataset[KeyUnion[(Apply[AssociationThread] @* Transpose) /@ 
                            Normal[dsApples[All, Lookup["params"] /* Values]],
                            Missing[] &]], 2];

tmp[All, {"Name", "COLOR", "EXP_DATE", "TYPE", "WEIGHT"}]

new Dataset

I'll leave the reformatting to a TableForm[] object up to you.


The difference between your two approaches is that in the first version, extracting parts of a dataset returns the part wrapped in Dataset while using the second approach, the part is not wrapped in Dataset. So, you can just add the Dataset wrapper yourself with:

dsAllAppleParamValues2 = dsAllApples[
    All,
    dsGetValueList[Dataset@#, dsApplesAllParams]&
] //Normal;

dsAllAppleParamValues == dsAllAppleParamValues2

True

That being said, the version without the Dataset head is probably easier to work with, so I would modify your dsGetValueList function to work with non-Dataset objects (in this case, just an Association).