So I've been toiling away on my DataFrame package. I've been trying to get Set
to work with it, but it seems it either can't be done (ie via UpValues
), or is ill advised. So I decided to bite the bullet and just roll my own custom DFSet
function. But I can't figure out how the get the evaluation to work like it does when you Set
the Part
of something.
This is my DFSet
function:
DFSet[Part[DataFrame[DFMetadata[metastore_], DFData[store_]], name_String], data_List] :=
(
If[
Length@data =!= metastore["Length"],
Abort[]
];
If[
!MemberQ[metastore["Names"], name],
metastore["Names"] = Append[metastore["Names"], name]
];
store[name] = Developer`ToPackedArray@data;
)
The idea is that it would be called like this:
DFSet[frame[["a"]], {1, 2, 3}]
The problem is that if I run it as is the Part
bit will try to evaluate and that won't do. But if I set the attribute HoldFirst
on DFSet
frame
won't evaluate to its OwnValue
.
A test case with code:
(****Code needed for a working test case but not part of the problem****)
(*Helper functions*)
StringVectorQ[x_] := MatchQ[x,{__String}]
TopMatrixQ[x_] := Length[Union@(Length/@x)]==1
(*Constructor*)
DataFrame[names_?StringVectorQ, data_?TopMatrixQ] :=
Module[
{store, metastore, length},
If[Length@First@data =!= Length@names, Abort[]];
store = Unique[DFstore];
metastore = Unique[DFmetastore];
metastore["Length"] = Length@First@Transpose@data;
metastore["Names"] = names;
Thread[
Set[#1,#2]&[store/@names, Developer`ToPackedArray/@Transpose@data]
];
DataFrame[DFMetadata[metastore], DFData[store]]
]
(*Pretty Formatting*)
Format[DataFrame[DFMetadata[metastore_], _DFData]] :=
"DataFrame"[Length[metastore["Names"]]]
(*UpValue for Part*)
DataFrame /: Part[DataFrame[DFMetadata[metastore_], DFData[store_]], name_String] :=
(
If[!MemberQ[metastore["Names"], name], Abort[]];
store[name]
)
(**************************)
(****The actual problem****)
(*DFSet function*)
DFSet[Part[DataFrame[DFMetadata[metastore_], DFData[store_]], name_String], data_List] :=
(
If[
Length@data =!= metastore["Length"],
Abort[]
];
If[
!MemberQ[metastore["Names"], name],
metastore["Names"] = Append[metastore["Names"], name]
];
store[name] = Developer`ToPackedArray@data;
)
(*******************)
(****A test case****)
(*Arrange*)
frame = DataFrame[{"a","b"},{{1,2},{1,2},{1,2}}]
(*Act*)
DFSet[frame[["c"]],{3,3,3}]
DFSet[frame[["b"]],{4,4,4}]
(*Assert*)
frame[["c"]]=={3,3,3}
frame[["b"]]=={4,4,4}
(****Output from successful test should be:
Out=DataFrame[2]
Out=True
Out=True
*)
frame
inframe[["a"]]
but notPart
, within yourDFSet
function. Is that correct? $\endgroup$