Nested templated data: Difference between revisions
(Added Bracmat solution) |
Not a robot (talk | contribs) (add SETL) |
||
(30 intermediate revisions by 18 users not shown) | |||
Line 13: | Line 13: | ||
;Task Detail: |
;Task Detail: |
||
Given the following input template <code>t</code> and list of payloads <code>p</code>: |
Given the following input template <code>t</code> and list of payloads <code>p</code>: |
||
<lang># Square brackets are used here to denote nesting but may be changed for other, |
<syntaxhighlight lang="text"># Square brackets are used here to denote nesting but may be changed for other, |
||
# clear, visual representations of nested data appropriate to ones programming |
# clear, visual representations of nested data appropriate to ones programming |
||
# language. |
# language. |
||
Line 21: | Line 21: | ||
5]] |
5]] |
||
p = 'Payload#0' ... 'Payload#6'</ |
p = 'Payload#0' ... 'Payload#6'</syntaxhighlight> |
||
The correct output should have the following structure, (although spacing and |
The correct output should have the following structure, (although spacing and |
||
linefeeds may differ, the nesting and order should follow): |
linefeeds may differ, the nesting and order should follow): |
||
<lang>[[['Payload#1', 'Payload#2'], |
<syntaxhighlight lang="text">[[['Payload#1', 'Payload#2'], |
||
['Payload#3', 'Payload#4', 'Payload#1'], |
['Payload#3', 'Payload#4', 'Payload#1'], |
||
'Payload#5']]</ |
'Payload#5']]</syntaxhighlight> |
||
1. Generate the output for the above template, <code>t</code>.<br> |
1. Generate the output for the above template, <code>t</code>.<br> |
||
Line 36: | Line 36: | ||
''Show output on this page.'' |
''Show output on this page.'' |
||
=={{header|AutoHotkey}}== |
|||
<syntaxhighlight lang="autohotkey">;----------------------------------------------------------- |
|||
Nested_templated_data(template, Payload){ |
|||
UsedP := [], UnusedP := [], UnusedI := [] |
|||
result := template.Clone() |
|||
x := ArrMap(template, Payload, result, UsedP, UnusedI, []) |
|||
for i, v in Payload |
|||
if !UsedP[v] |
|||
UnusedP.Push(v) |
|||
return [x.1, x.2, UnusedP] |
|||
} |
|||
;----------------------------------------------------------- |
|||
ArrMap(Template, Payload, result, UsedP, UnusedI, pth){ |
|||
for i, index in Template { |
|||
if IsObject(index) |
|||
pth.Push(i), Arrmap(index, Payload, result, UsedP, UnusedI, pth) |
|||
else{ |
|||
pth.Push(i), ArrSetPath(result, pth, Payload[index]) |
|||
if Payload[index] |
|||
UsedP[Payload[index]] := 1 |
|||
else |
|||
UnusedI.Push(index) |
|||
} |
|||
pth.Pop() |
|||
} |
|||
return [result, UnusedI, UsedP] |
|||
} |
|||
;----------------------------------------------------------- |
|||
ArrSetPath(Arr, pth, newVal){ |
|||
temp := [] |
|||
for k, v in pth{ |
|||
temp.push(v) |
|||
if !IsObject(Arr[temp*]) |
|||
Arr[temp*] := [] |
|||
} |
|||
return Arr[temp*] := newVal |
|||
} |
|||
;----------------------------------------------------------- |
|||
objcopy(obj){ |
|||
nobj := obj.Clone() |
|||
for k, v in nobj |
|||
if IsObject(v) |
|||
nobj[k] := objcopy(v) |
|||
return nobj |
|||
} |
|||
;-----------------------------------------------------------</syntaxhighlight> |
|||
Examples:<syntaxhighlight lang="autohotkey">T := [[[1,2] , [3,4,1] , 5]] |
|||
; Autohotkey uses 1-based objects/arrays |
|||
P := ["Payload#1", "Payload#2", "Payload#3", "Payload#4", "Payload#5", "Payload#6", "Payload#7"] |
|||
Results := Nested_templated_data(objcopy(t), P) |
|||
output := Results.1 |
|||
Undefined_indices := Results[2] |
|||
Unused_Payloads := Results[3]</syntaxhighlight> |
|||
{{out}} |
|||
<pre>T := [[[1,2] , [3,4,1] , 5]] |
|||
P := ["Payload#1", "Payload#2", "Payload#3", "Payload#4", "Payload#5", "Payload#6", "Payload#7"] |
|||
output : [[["payload#1", "payload#2"] , ["payload#3", "payload#4", "payload#1"] , "payload#5"]] |
|||
Undefined_indices : [] |
|||
Unused_Payloads : ["Payload#6", "Payload#7"] |
|||
;----------------------------------------------------------- |
|||
T := [[[1,2] , [3,4,1,8] , 5]] |
|||
P := ["Payload#1", "Payload#2", "Payload#3", "Payload#4", "Payload#5", "Payload#6", "Payload#7"] |
|||
output : [[["payload#1", "payload#2"] , ["payload#3", "payload#4", "payload#1", ""] , "payload#5"]] |
|||
Undefined_indices : [8] |
|||
Unused_Payloads : ["Payload#6", "Payload#7"]</pre> |
|||
=={{header|BASIC}}== |
|||
==={{header|Applesoft BASIC}}=== |
|||
The [[#GW-BASIC|GW-BASIC]] solution works without any changes. |
|||
==={{header|BASIC256}}=== |
|||
{{trans|FreeBASIC}} |
|||
<syntaxhighlight lang="vbnet">dim p(7) |
|||
dim p$(7) |
|||
p$[0] = "Payload#0" : p$[1] = "Payload#1" |
|||
p$[2] = "Payload#2" : p$[3] = "Payload#3" |
|||
p$[4] = "Payload#4" : p$[5] = "Payload#5" |
|||
p$[6] = "Payload#6" |
|||
dim q(7) fill false |
|||
dim t(4, 5) |
|||
t[0, 0] = 1: t[0, 1] = 2 |
|||
t[1, 0] = 3: t[1, 1] = 4: t[1, 2] = 1 |
|||
t[2, 0] = 5 |
|||
for i = 0 to t[?][]-1 |
|||
for j = 0 to t[?][]-1 |
|||
if t[i, j] <> 0 then |
|||
q[t[i, j]] = true |
|||
t[i, j] += 1 |
|||
end if |
|||
next j |
|||
next i |
|||
for i = 0 to t[?][]-1 |
|||
for j = 0 to t[?][]-1 |
|||
if t[i, j] <> 0 then print p$[t[i, j] -1]; " "; |
|||
next j |
|||
print |
|||
next i |
|||
for i = 0 to q[?]-1 |
|||
if not q[i] then print p$[i]; " is not used" |
|||
next i</syntaxhighlight> |
|||
{{out}} |
|||
<pre>Same as FreeBASIC entry.</pre> |
|||
==={{header|Chipmunk Basic}}=== |
|||
{{trans|FreeBASIC}} |
|||
{{works with|Chipmunk Basic|3.6.4}} |
|||
<syntaxhighlight lang="vbnet">100 cls |
|||
110 dim i,j,p(6) |
|||
120 dim p$(6) |
|||
130 p$(0) = "Payload#0" : p$(1) = "Payload#1" |
|||
140 p$(2) = "Payload#2" : p$(3) = "Payload#3" |
|||
150 p$(4) = "Payload#4" : p$(5) = "Payload#5" |
|||
160 p$(6) = "Payload#6" |
|||
170 dim q(6) |
|||
180 dim t(2,3) |
|||
190 t(0,0) = 1 : t(0,1) = 2 |
|||
200 t(1,0) = 3 : t(1,1) = 4 : t(1,2) = 1 |
|||
210 t(2,0) = 5 |
|||
220 for i = 0 to ubound(t) |
|||
230 for j = 0 to ubound(t,2) |
|||
240 if t(i,j) <> 0 then |
|||
250 q(t(i,j)) = true |
|||
260 t(i,j) = t(i,j)+1 |
|||
270 endif |
|||
280 next j |
|||
290 next i |
|||
300 for i = 0 to ubound(t) |
|||
310 for j = 0 to ubound(t,2) |
|||
320 if t(i,j) <> 0 then print p$(t(i,j)-1);" "; |
|||
330 next j |
|||
340 print |
|||
350 next i |
|||
360 for i = 0 to ubound(q) |
|||
370 if not q(i) then print p$(i);" is not used" |
|||
380 next i |
|||
390 end</syntaxhighlight> |
|||
{{out}} |
|||
<pre>Same as FreeBASIC entry.</pre> |
|||
==={{header|FreeBASIC}}=== |
|||
{{trans|Ring}} |
|||
<syntaxhighlight lang="vbnet">Dim As Integer t(2, 3) = {{1,2},{3,4,1},{5}} |
|||
Dim As Integer i, j, p(6) |
|||
Dim As String pStr(6) = {"Payload#0", "Payload#1", "Payload#2", "Payload#3", "Payload#4", "Payload#5", "Payload#6"} |
|||
Dim As Boolean q(6) |
|||
For i = Lbound(t) To Ubound(t) |
|||
For j = Lbound(t, 2) To Ubound(t, 2) |
|||
If t(i, j) <> 0 Then |
|||
q(t(i, j)) = True |
|||
t(i, j) += 1 |
|||
End If |
|||
Next j |
|||
Next i |
|||
For i = Lbound(t) To Ubound(t) |
|||
For j = Lbound(t, 2) To Ubound(t, 2) |
|||
If t(i, j) <> 0 Then Print pStr(t(i, j)-1); " "; |
|||
Next j |
|||
Print |
|||
Next i |
|||
For i = Lbound(q) To Ubound(q) |
|||
If q(i) = False Then Print pStr(i); " is not used" |
|||
Next i |
|||
Sleep</syntaxhighlight> |
|||
{{out}} |
|||
<pre>Payload#1 Payload#2 |
|||
Payload#3 Payload#4 Payload#1 |
|||
Payload#5 |
|||
Payload#0 is not used |
|||
Payload#6 is not used</pre> |
|||
==={{header|GW-BASIC}}=== |
|||
{{trans|FreeBASIC}} |
|||
{{works with|PC-BASIC|any}} |
|||
{{works with|BASICA}} |
|||
{{works with|Applesoft BASIC}} |
|||
{{works with|Chipmunk Basic}} |
|||
{{works with|MSX BASIC}} |
|||
{{works with|QBasic}} |
|||
{{works with|QB64}} |
|||
<syntaxhighlight lang="qbasic">110 TRUE = -1 |
|||
120 FALSE = NOT TRUE |
|||
130 DIM I,J,P(6) |
|||
140 DIM P$(6) |
|||
150 P$(0) = "Payload#0" : P$(1) = "Payload#1" |
|||
160 P$(2) = "Payload#2" : P$(3) = "Payload#3" |
|||
170 P$(4) = "Payload#4" : P$(5) = "Payload#5" |
|||
180 P$(6) = "Payload#6" |
|||
190 DIM Q(6) |
|||
200 DIM T(2,3) |
|||
210 T(0,0) = 1 : T(0,1) = 2 |
|||
220 T(1,0) = 3 : T(1,1) = 4 : T(1,2) = 1 |
|||
230 T(2,0) = 5 |
|||
240 FOR I = 0 TO 2 |
|||
250 FOR J = 0 TO 3 |
|||
260 IF T(I,J) <> 0 THEN Q(T(I,J)) = TRUE : T(I,J) = T(I,J)+1 |
|||
270 NEXT J |
|||
280 NEXT I |
|||
290 FOR I = 0 TO 2 |
|||
300 FOR J = 0 TO 3 |
|||
310 IF T(I,J) <> 0 THEN PRINT P$(T(I,J)-1);" "; |
|||
320 NEXT J |
|||
330 PRINT |
|||
340 NEXT I |
|||
350 FOR I = 0 TO 6 |
|||
360 IF Q(I) = FALSE THEN PRINT P$(I);" is not used" |
|||
370 NEXT I |
|||
380 END</syntaxhighlight> |
|||
{{out}} |
|||
<pre>Same as FreeBASIC entry.</pre> |
|||
==={{header|MSX Basic}}=== |
|||
{{works with|MSX BASIC|any}} |
|||
The [[#GW-BASIC|GW-BASIC]] solution works without any changes. |
|||
==={{header|QBasic}}=== |
|||
{{works with|QBasic|1.1}} |
|||
{{works with|QuickBasic|4.5}} |
|||
{{works with|QB64}} |
|||
<syntaxhighlight lang="qbasic">True = -1: False = NOT True |
|||
DIM p(6) |
|||
DIM p$(6) |
|||
p$(0) = "Payload#0": p$(1) = "Payload#1" |
|||
p$(2) = "Payload#2": p$(3) = "Payload#3" |
|||
p$(4) = "Payload#4": p$(5) = "Payload#5" |
|||
p$(6) = "Payload#6" |
|||
DIM q(6) |
|||
DIM t(2, 3) |
|||
t(0, 0) = 1: t(0, 1) = 2 |
|||
t(1, 0) = 3: t(1, 1) = 4: t(1, 2) = 1 |
|||
t(2, 0) = 5 |
|||
FOR i = LBOUND(t) TO UBOUND(t) '0 To 2 |
|||
FOR j = LBOUND(t, 2) TO UBOUND(t, 2) '0 To 3 |
|||
IF t(i, j) <> 0 THEN |
|||
q(t(i, j)) = True |
|||
t(i, j) = t(i, j) + 1 |
|||
END IF |
|||
NEXT j |
|||
NEXT i |
|||
FOR i = LBOUND(t) TO UBOUND(t) '0 To 2 |
|||
FOR j = LBOUND(t, 2) TO UBOUND(t, 2) '0 To 3 |
|||
IF t(i, j) <> 0 THEN PRINT p$(t(i, j) - 1); " "; |
|||
NEXT j |
|||
PRINT |
|||
NEXT i |
|||
FOR i = LBOUND(q) TO UBOUND(q) |
|||
IF q(i) = False THEN PRINT p$(i); " is not used" |
|||
NEXT i</syntaxhighlight> |
|||
{{out}} |
|||
<pre>Same as FreeBASIC entry.</pre> |
|||
==={{header|QB64}}=== |
|||
The [[#QBasic|QBasic]] solution works without any changes. |
|||
==={{header|Run BASIC}}=== |
|||
{{trans|QBasic}} |
|||
{{works with|Just BASIC}} |
|||
{{works with|Liberty BASIC}} |
|||
{{works with|QBasic}} |
|||
{{works with|QB64}} |
|||
<syntaxhighlight lang="qbasic">DIM p(6) |
|||
DIM p$(6) |
|||
p$(0) = "Payload#0": p$(1) = "Payload#1" |
|||
p$(2) = "Payload#2": p$(3) = "Payload#3" |
|||
p$(4) = "Payload#4": p$(5) = "Payload#5" |
|||
p$(6) = "Payload#6" |
|||
DIM q(6) |
|||
DIM t(2, 3) |
|||
t(0, 0) = 1: t(0, 1) = 2 |
|||
t(1, 0) = 3: t(1, 1) = 4: t(1, 2) = 1 |
|||
t(2, 0) = 5 |
|||
FOR i = 0 TO 2 |
|||
FOR j = 0 TO 3 |
|||
IF t(i, j) <> 0 THEN |
|||
q(t(i, j)) = -1 |
|||
t(i, j) = t(i, j) + 1 |
|||
END IF |
|||
NEXT j |
|||
NEXT i |
|||
FOR i = 0 TO 2 |
|||
FOR j = 0 TO 3 |
|||
IF t(i, j) <> 0 THEN PRINT p$(t(i, j) - 1); " "; |
|||
NEXT j |
|||
PRINT |
|||
NEXT i |
|||
FOR i = 0 TO 6 |
|||
IF q(i) = 0 THEN PRINT p$(i); " is not used" |
|||
NEXT i</syntaxhighlight> |
|||
{{out}} |
|||
<pre>Same as QBasic entry.</pre> |
|||
==={{header|Yabasic}}=== |
|||
{{trans|FreeBASIC}} |
|||
<syntaxhighlight lang="vbnet">dim p(6) |
|||
dim p$(6) |
|||
p$(0) = "Payload#0" : p$(1) = "Payload#1" |
|||
p$(2) = "Payload#2" : p$(3) = "Payload#3" |
|||
p$(4) = "Payload#4" : p$(5) = "Payload#5" |
|||
p$(6) = "Payload#6" |
|||
dim q(6) |
|||
dim t(2, 3) |
|||
t(0, 0) = 1: t(0, 1) = 2 |
|||
t(1, 0) = 3: t(1, 1) = 4: t(1, 2) = 1 |
|||
t(2, 0) = 5 |
|||
for i = 0 to arraysize(t(), 1) |
|||
for j = 0 to arraysize(t(), 2) |
|||
if t(i, j) <> 0 then |
|||
q(t(i, j)) = True |
|||
t(i, j) = t(i, j) + 1 |
|||
fi |
|||
next j |
|||
next i |
|||
for i = 0 to arraysize(t(), 1) |
|||
for j = 0 to arraysize(t(), 2) |
|||
if t(i, j) <> 0 print p$(t(i, j) -1), " "; |
|||
next j |
|||
print |
|||
next i |
|||
for i = 0 to arraysize(q(), 1) |
|||
if not q(i) print p$(i), " is not used" |
|||
next i</syntaxhighlight> |
|||
{{out}} |
|||
<pre>Same as FreeBASIC entry.</pre> |
|||
=={{header|Bracmat}}== |
=={{header|Bracmat}}== |
||
The uninstantiated template and the instantiated template are JSON structures. The payloads are listed in a Bracmat list. The <code>get</code> function is instructed to read input from memory and to parse it as JSON. The output of this call is a Bracmat structure (not shown) that is assigned to <code>template</code>. The <code>instantiate</code> function recursively traverses the template's tree structure. If the current node is a number, then that number is used as the key into the payloads list. The corresponding payload is then returned. If the current node is not a number, then it is assumed that the current node is a binary (sub)tree. The left hand side (called <code>a</code>) and the right hand side (called <code>b</code>) are instantiated and their combination is returned. Finally the instantiated tree is transformed back to JSON format and output. |
The uninstantiated template and the instantiated template are JSON structures. The payloads are listed in a Bracmat list. The <code>get</code> function is instructed to read input from memory and to parse it as JSON. The output of this call is a Bracmat structure (not shown) that is assigned to <code>template</code>. The <code>instantiate</code> function recursively traverses the template's tree structure. If the current node is a number, then that number is used as the key into the payloads list. The corresponding payload is then returned. If the current node is not a number, then it is assumed that the current node is a binary (sub)tree. The left hand side (called <code>a</code>) and the right hand side (called <code>b</code>) are instantiated and their combination is returned. Finally the instantiated tree is transformed back to JSON format and output. |
||
< |
<syntaxhighlight lang="bracmat">( get$("[ |
||
[[1, 2], |
[[1, 2], |
||
[3, 4, 1], |
[3, 4, 1], |
||
Line 62: | Line 403: | ||
) |
) |
||
& out$(jsn$(instantiate$(!template.!payloads))) |
& out$(jsn$(instantiate$(!template.!payloads))) |
||
);</ |
);</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
<pre>[[[payload#1,payload#2],[payload#3,payload#4,payload#1],payload#5]]</pre> |
<pre>[[[payload#1,payload#2],[payload#3,payload#4,payload#1],payload#5]]</pre> |
||
=={{header|C++}}== |
|||
Uses C++17 or later. |
|||
The nested indexes are defined by tuples from the standard library. C++ function templates recursively traverse the tuple structure and map to the payloads. |
|||
<syntaxhighlight lang="cpp">#include <iostream> |
|||
#include <set> |
|||
#include <tuple> |
|||
#include <vector> |
|||
using namespace std; |
|||
// print a single payload |
|||
template<typename P> |
|||
void PrintPayloads(const P &payloads, int index, bool isLast) |
|||
{ |
|||
if(index < 0 || index >= (int)size(payloads)) cout << "null"; |
|||
else cout << "'" << payloads[index] << "'"; |
|||
if (!isLast) cout << ", "; // add a comma between elements |
|||
} |
|||
// print a tuple of playloads |
|||
template<typename P, typename... Ts> |
|||
void PrintPayloads(const P &payloads, tuple<Ts...> const& nestedTuple, bool isLast = true) |
|||
{ |
|||
std::apply // recursively call PrintPayloads on each element of the tuple |
|||
( |
|||
[&payloads, isLast](Ts const&... tupleArgs) |
|||
{ |
|||
size_t n{0}; |
|||
cout << "["; |
|||
(PrintPayloads(payloads, tupleArgs, (++n == sizeof...(Ts)) ), ...); |
|||
cout << "]"; |
|||
cout << (isLast ? "\n" : ",\n"); |
|||
}, nestedTuple |
|||
); |
|||
} |
|||
// find the unique index of a single index (helper for the function below) |
|||
void FindUniqueIndexes(set<int> &indexes, int index) |
|||
{ |
|||
indexes.insert(index); |
|||
} |
|||
// find the unique indexes in the tuples |
|||
template<typename... Ts> |
|||
void FindUniqueIndexes(set<int> &indexes, std::tuple<Ts...> const& nestedTuple) |
|||
{ |
|||
std::apply |
|||
( |
|||
[&indexes](Ts const&... tupleArgs) |
|||
{ |
|||
(FindUniqueIndexes(indexes, tupleArgs),...); |
|||
}, nestedTuple |
|||
); |
|||
} |
|||
// print the payloads that were not used |
|||
template<typename P> |
|||
void PrintUnusedPayloads(const set<int> &usedIndexes, const P &payloads) |
|||
{ |
|||
for(size_t i = 0; i < size(payloads); i++) |
|||
{ |
|||
if(usedIndexes.find(i) == usedIndexes.end() ) cout << payloads[i] << "\n"; |
|||
} |
|||
} |
|||
int main() |
|||
{ |
|||
// define the playloads, they can be in most containers |
|||
vector payloads {"Payload#0", "Payload#1", "Payload#2", "Payload#3", "Payload#4", "Payload#5", "Payload#6"}; |
|||
const char *shortPayloads[] {"Payload#0", "Payload#1", "Payload#2", "Payload#3"}; // as a C array |
|||
// define the indexes as a nested tuple |
|||
auto tpl = make_tuple(make_tuple( |
|||
make_tuple(1, 2), |
|||
make_tuple(3, 4, 1), |
|||
5)); |
|||
cout << "Mapping indexes to payloads:\n"; |
|||
PrintPayloads(payloads, tpl); |
|||
cout << "\nFinding unused payloads:\n"; |
|||
set<int> usedIndexes; |
|||
FindUniqueIndexes(usedIndexes, tpl); |
|||
PrintUnusedPayloads(usedIndexes, payloads); |
|||
cout << "\nMapping to some out of range payloads:\n"; |
|||
PrintPayloads(shortPayloads, tpl); |
|||
return 0; |
|||
}</syntaxhighlight> |
|||
{{out}} |
|||
<pre> |
|||
Mapping indexes to payloads: |
|||
[[['Payload#1', 'Payload#2'], |
|||
['Payload#3', 'Payload#4', 'Payload#1'], |
|||
'Payload#5'] |
|||
] |
|||
Finding unused payloads: |
|||
Payload#0 |
|||
Payload#6 |
|||
Mapping to some out of range payloads: |
|||
[[['Payload#1', 'Payload#2'], |
|||
['Payload#3', null, 'Payload#1'], |
|||
null] |
|||
] |
|||
</pre> |
|||
=={{header|Crystal}}== |
|||
<syntaxhighlight lang="ruby">def with_payload(template, payload, used = nil) |
|||
template.map do |item| |
|||
if item.is_a? Enumerable |
|||
with_payload(item, payload, used) |
|||
else |
|||
used << item |
|||
payload[item] |
|||
end |
|||
end |
|||
end |
|||
p = {"Payload#0", "Payload#1", "Payload#2", "Payload#3", "Payload#4", "Payload#5", "Payload#6"} |
|||
t = { { {1, 2}, {3, 4, 1}, 5}} |
|||
used = Set(Int32).new |
|||
puts with_payload(t, p, used) |
|||
unused = Set(Int32).new((0..6).to_a) - used |
|||
puts "Unused indices: #{unused}"</syntaxhighlight> |
|||
{{out}} |
|||
<pre>{{{"Payload#1", "Payload#2"}, {"Payload#3", "Payload#4", "Payload#1"}, "Payload#5"}} |
|||
Unused indices: Set{0, 6}</pre> |
|||
=={{header|Factor}}== |
=={{header|Factor}}== |
||
Words for traversing nested sequences can be found in the <code>sequences.deep</code> vocabulary. Factor's prettyprinter attempts to print structures on a single line (64 characters by default, though this can be changed) if they will fit. Otherwise, the prettyprinter will break them up into multiple lines, preferring to show one member per line if possible. <code>f</code>, Factor's false/nil value, is used to indicate a missing payload. |
Words for traversing nested sequences can be found in the <code>sequences.deep</code> vocabulary. Factor's prettyprinter attempts to print structures on a single line (64 characters by default, though this can be changed) if they will fit. Otherwise, the prettyprinter will break them up into multiple lines, preferring to show one member per line if possible. <code>f</code>, Factor's false/nil value, is used to indicate a missing payload. |
||
< |
<syntaxhighlight lang="factor">USING: formatting kernel literals math sequences sequences.deep ; |
||
IN: rosetta-code.nested-template-data |
IN: rosetta-code.nested-template-data |
||
Line 85: | Line 562: | ||
[ dup insert-payloads "Template: %u\nData Structure: %u\n" |
[ dup insert-payloads "Template: %u\nData Structure: %u\n" |
||
printf ] bi@</ |
printf ] bi@</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
<pre> |
<pre> |
||
Line 109: | Line 586: | ||
Go's standard library includes a "text/template" package which can be used for this task. |
Go's standard library includes a "text/template" package which can be used for this task. |
||
<br> |
<br> |
||
The integer indices are represented by the keys of a map whose corresponding value is the appropriate payload string. Templates have their own mini-language and, for a map P with key n, the expression: <lang |
The integer indices are represented by the keys of a map whose corresponding value is the appropriate payload string. Templates have their own mini-language and, for a map P with key n, the expression: <syntaxhighlight lang="html">{{index .P n}}</syntaxhighlight> will be replaced by the corresponding payload. |
||
<br> |
<br> |
||
If an integer index either doesn't exist in the map or maps to an empty payload, then the above expression will simply be replaced by an empty string when the template is executed. |
If an integer index either doesn't exist in the map or maps to an empty payload, then the above expression will simply be replaced by an empty string when the template is executed. |
||
< |
<syntaxhighlight lang="go">package main |
||
import ( |
import ( |
||
Line 147: | Line 624: | ||
sort.Ints(unused) |
sort.Ints(unused) |
||
fmt.Println("\nThe unused payloads have indices of :", unused) |
fmt.Println("\nThe unused payloads have indices of :", unused) |
||
}</ |
}</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
Line 158: | Line 635: | ||
</pre> |
</pre> |
||
=={{header|Haskell}}== |
|||
The problem is ideal for demonstrating the Functor and Traversable concepts. |
|||
Being a ''functor'' allows changing the contents of a complex data structure, keeping structure unchanged (via <tt>fmap</tt> function). This property already matches the template idea, but we can go further. The structure may be ''foldable'' as well, allowing aggregation of contents, using arbitrary monoid or aggregating function. Moreover foldable functor may be ''traversable'', giving the ability to modify the complex structure contents with computations held in a given applicative or monadic context. |
|||
All these properties are well defined, have solid theoretical background and are presented by classes: <tt>Functor</tt>, <tt>Foldable</tt> and <tt>Traversable</tt>. |
|||
For wide class of data structures instances of all these classes may be derived by the compiler in a sound unique way. The data template given in the task is exactly the case of a functor. |
|||
If we do not bother about neat textual representation, the definition of traversable nested template is as easy as following: |
|||
<syntaxhighlight lang="haskell">{-# language DeriveTraversable #-} |
|||
data Template a = Val a | List [Template a] |
|||
deriving ( Show |
|||
, Functor |
|||
, Foldable |
|||
, Traversable )</syntaxhighlight> |
|||
Functorial property of a data type is sufficient for defining the universal substitutor of keys/indices by payload data: |
|||
<syntaxhighlight lang="haskell">subst :: (Functor t, Eq i) => [(i,a)] -> t i -> t (Maybe a) |
|||
subst d = fmap (`lookup` d)</syntaxhighlight> |
|||
It is possible to turn any list of payloads into a map by simple helper function: |
|||
<syntaxhighlight lang="haskell">indexed :: [a] -> [(Int, a)] |
|||
indexed = zip [0..]</syntaxhighlight> |
|||
Now we can make substitutions to flat lists or nested templates: |
|||
<syntaxhighlight lang="haskell">t :: Template Int |
|||
t = List [ List [Val 1, Val 2] |
|||
, List [Val 3, Val 4, Val 10] |
|||
, Val 5] |
|||
payloads :: [(Int, String)] |
|||
payloads = [(i, "payload#"++show i) | i <- [0..6]]</syntaxhighlight> |
|||
<pre>λ> subst payloads [6,2,1,2] |
|||
[Just "payload#6",Just "payload#2",Just "payload#1",Just "payload#2"] |
|||
λ> sequence $ subst payloads [6,2,1,2] |
|||
Just ["payload#6","payload#2","payload#1","payload#2"] |
|||
λ> indexed "traverse" |
|||
[(0,'t'),(1,'r'),(2,'a'),(3,'v'),(4,'e'),(5,'r'),(6,'s'),(7,'e')] |
|||
λ> subst (indexed "traverse") [6,7,1,3,4,1] |
|||
[Just 's',Just 'e',Just 'r',Just 'v',Just 'e',Just 'r'] |
|||
λ> sequence . subst (indexed "traverse") [6,7,1,3,4,1] |
|||
Just "server" |
|||
λ> subst payloads t |
|||
List [ List [Val (Just "payload#1"),Val (Just "payload#2")] |
|||
, List [Val (Just "payload#3"),Val (Just "payload#4"),Val Nothing] |
|||
, Val (Just "payload#5")] |
|||
λ> sequence $ subst payloads t |
|||
Nothing</pre> |
|||
In the last case not all substitutions could be done, so the whole substitution failed. The <tt>sequence</tt> function works for any traversable structures. |
|||
Foldable properties of templates (with a little help of monoids) allow to implement extended tasks. |
|||
<syntaxhighlight lang="haskell">unusedIndices :: (Foldable t, Eq i) => [(i,a)] -> t i -> [i] |
|||
unusedIndices d = foldMap unused |
|||
where unused i = maybe (pure i) (pure []) $ lookup i d |
|||
unusedData :: (Foldable t, Eq i) => [(i, a)] -> t i -> [(i,a)] |
|||
unusedData = foldr delete |
|||
where delete i = filter ((i /= ) . fst) </syntaxhighlight> |
|||
<pre>λ> unusedIndices payloads t |
|||
[10] |
|||
λ> unusedData payloads t |
|||
[(0,"payload#0"),(6,"payload#6")]</pre> |
|||
=={{header|J}}== |
|||
===Group substitution=== |
|||
<pre> |
|||
Substitute=: ({.@:[)`(I.@:(= {:)~)`]} |
|||
NB. aside: demonstrate Substitution |
|||
] A =: ;/ i. 8 |
|||
┌─┬─┬─┬─┬─┬─┬─┬─┐ |
|||
│0│1│2│3│4│5│6│7│ |
|||
└─┴─┴─┴─┴─┴─┴─┴─┘ |
|||
] B =: ('xxxx' ; 3) |
|||
┌────┬─┐ |
|||
│xxxx│3│ |
|||
└────┴─┘ |
|||
B Substitute A |
|||
┌─┬─┬─┬────┬─┬─┬─┬─┐ |
|||
│0│1│2│xxxx│4│5│6│7│ |
|||
└─┴─┴─┴────┴─┴─┴─┴─┘ |
|||
B Substitute A , < 3 |
|||
┌─┬─┬─┬────┬─┬─┬─┬─┬────┐ |
|||
│0│1│2│xxxx│4│5│6│7│xxxx│ |
|||
└─┴─┴─┴────┴─┴─┴─┴─┴────┘ |
|||
</pre> |
|||
===Convert template to j structured data=== |
|||
<pre> |
|||
NB. algorithm: evaluate after rewrite as a j sentence |
|||
NB. the result is an actual structured noun. |
|||
NB. because arrays are homogeneous in data type |
|||
NB. 1) data type validity for an operation takes place just once for all the values in the array which is fast |
|||
NB. 2) but a box next to a 5 is invalid. |
|||
NB. hence the payloads must be individually boxed as well. |
|||
] p =: ('(<''payload#',''')',~":)&>i.7 |
|||
(<'payload#0') |
|||
(<'payload#1') |
|||
(<'payload#2') |
|||
(<'payload#3') |
|||
(<'payload#4') |
|||
(<'payload#5') |
|||
(<'payload#6') |
|||
NB. though they look scalar the words are vector |
|||
] t =: ;: CRLF -.~ 0 :0 |
|||
[ |
|||
[[1, 2], |
|||
[3, 4, 1], |
|||
5]] |
|||
) |
|||
┌─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┐ |
|||
│[│[│[│1│,│2│]│,│[│3│,│4│,│1│]│,│5│]│]│ |
|||
└─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┘ |
|||
t =: ,: t NB. itemize t, then append successive substitutions |
|||
t =: t , ('(<' ; , '[') Substitute {: t |
|||
t =: t , ( ')' ; , ']') Substitute {: t |
|||
t |
|||
┌──┬──┬──┬─┬─┬─┬─┬─┬──┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┐ |
|||
│[ │[ │[ │1│,│2│]│,│[ │3│,│4│,│1│]│,│5│]│]│ |
|||
├──┼──┼──┼─┼─┼─┼─┼─┼──┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┤ |
|||
│(<│(<│(<│1│,│2│]│,│(<│3│,│4│,│1│]│,│5│]│]│ |
|||
├──┼──┼──┼─┼─┼─┼─┼─┼──┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┤ |
|||
│(<│(<│(<│1│,│2│)│,│(<│3│,│4│,│1│)│,│5│)│)│ |
|||
└──┴──┴──┴─┴─┴─┴─┴─┴──┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┘ |
|||
NB. finish the substitutions in one fell swoop |
|||
] SUBSTITUTIONS=: (<"1 p) ,. ,@":&.> i.7 |
|||
┌──────────────┬─┐ |
|||
│(<'payload#0')│0│ |
|||
├──────────────┼─┤ |
|||
│(<'payload#1')│1│ |
|||
├──────────────┼─┤ |
|||
│(<'payload#2')│2│ |
|||
├──────────────┼─┤ |
|||
│(<'payload#3')│3│ |
|||
├──────────────┼─┤ |
|||
│(<'payload#4')│4│ |
|||
├──────────────┼─┤ |
|||
│(<'payload#5')│5│ |
|||
├──────────────┼─┤ |
|||
│(<'payload#6')│6│ |
|||
└──────────────┴─┘ |
|||
[ t =: > (] , (Substitute {:))&.>/(<"1 SUBSTITUTIONS) , < t |
|||
┌──┬──┬──┬──────────────┬─┬──────────────┬─┬─┬──┬──────────────┬─┬──────────────┬─┬──────────────┬─┬─┬──────────────┬─┬─┐ |
|||
│[ │[ │[ │1 │,│2 │]│,│[ │3 │,│4 │,│1 │]│,│5 │]│]│ |
|||
├──┼──┼──┼──────────────┼─┼──────────────┼─┼─┼──┼──────────────┼─┼──────────────┼─┼──────────────┼─┼─┼──────────────┼─┼─┤ |
|||
│(<│(<│(<│1 │,│2 │]│,│(<│3 │,│4 │,│1 │]│,│5 │]│]│ |
|||
├──┼──┼──┼──────────────┼─┼──────────────┼─┼─┼──┼──────────────┼─┼──────────────┼─┼──────────────┼─┼─┼──────────────┼─┼─┤ |
|||
│(<│(<│(<│1 │,│2 │)│,│(<│3 │,│4 │,│1 │)│,│5 │)│)│ |
|||
├──┼──┼──┼──────────────┼─┼──────────────┼─┼─┼──┼──────────────┼─┼──────────────┼─┼──────────────┼─┼─┼──────────────┼─┼─┤ |
|||
│(<│(<│(<│1 │,│2 │)│,│(<│3 │,│4 │,│1 │)│,│5 │)│)│ |
|||
├──┼──┼──┼──────────────┼─┼──────────────┼─┼─┼──┼──────────────┼─┼──────────────┼─┼──────────────┼─┼─┼──────────────┼─┼─┤ |
|||
│(<│(<│(<│1 │,│2 │)│,│(<│3 │,│4 │,│1 │)│,│(<'payload#5')│)│)│ |
|||
├──┼──┼──┼──────────────┼─┼──────────────┼─┼─┼──┼──────────────┼─┼──────────────┼─┼──────────────┼─┼─┼──────────────┼─┼─┤ |
|||
│(<│(<│(<│1 │,│2 │)│,│(<│3 │,│(<'payload#4')│,│1 │)│,│(<'payload#5')│)│)│ |
|||
├──┼──┼──┼──────────────┼─┼──────────────┼─┼─┼──┼──────────────┼─┼──────────────┼─┼──────────────┼─┼─┼──────────────┼─┼─┤ |
|||
│(<│(<│(<│1 │,│2 │)│,│(<│(<'payload#3')│,│(<'payload#4')│,│1 │)│,│(<'payload#5')│)│)│ |
|||
├──┼──┼──┼──────────────┼─┼──────────────┼─┼─┼──┼──────────────┼─┼──────────────┼─┼──────────────┼─┼─┼──────────────┼─┼─┤ |
|||
│(<│(<│(<│1 │,│(<'payload#2')│)│,│(<│(<'payload#3')│,│(<'payload#4')│,│1 │)│,│(<'payload#5')│)│)│ |
|||
├──┼──┼──┼──────────────┼─┼──────────────┼─┼─┼──┼──────────────┼─┼──────────────┼─┼──────────────┼─┼─┼──────────────┼─┼─┤ |
|||
│(<│(<│(<│(<'payload#1')│,│(<'payload#2')│)│,│(<│(<'payload#3')│,│(<'payload#4')│,│(<'payload#1')│)│,│(<'payload#5')│)│)│ |
|||
├──┼──┼──┼──────────────┼─┼──────────────┼─┼─┼──┼──────────────┼─┼──────────────┼─┼──────────────┼─┼─┼──────────────┼─┼─┤ |
|||
│(<│(<│(<│(<'payload#1')│,│(<'payload#2')│)│,│(<│(<'payload#3')│,│(<'payload#4')│,│(<'payload#1')│)│,│(<'payload#5')│)│)│ |
|||
└──┴──┴──┴──────────────┴─┴──────────────┴─┴─┴──┴──────────────┴─┴──────────────┴─┴──────────────┴─┴─┴──────────────┴─┴─┘ |
|||
] TASK=: ". ;:inv {: t NB. task output |
|||
┌───────────────────────────────────────────────────────────────────┐ |
|||
│┌─────────────────────────────────────────────────────────────────┐│ |
|||
││┌─────────────────────┬───────────────────────────────┬─────────┐││ |
|||
│││┌─────────┬─────────┐│┌─────────┬─────────┬─────────┐│payload#5│││ |
|||
││││payload#1│payload#2│││payload#3│payload#4│payload#1││ │││ |
|||
│││└─────────┴─────────┘│└─────────┴─────────┴─────────┘│ │││ |
|||
││└─────────────────────┴───────────────────────────────┴─────────┘││ |
|||
│└─────────────────────────────────────────────────────────────────┘│ |
|||
└───────────────────────────────────────────────────────────────────┘ |
|||
</pre> |
|||
===Explorations=== |
|||
<pre> |
|||
L. TASK NB. level |
|||
4 |
|||
<S:1 TASK NB. spread boxing at level 1 |
|||
┌─────────────────────┬───────────────────────────────┬─────────┐ |
|||
│┌─────────┬─────────┐│┌─────────┬─────────┬─────────┐│payload#5│ |
|||
││payload#1│payload#2│││payload#3│payload#4│payload#1││ │ |
|||
│└─────────┴─────────┘│└─────────┴─────────┴─────────┘│ │ |
|||
└─────────────────────┴───────────────────────────────┴─────────┘ |
|||
[S:0 TASK NB. leaves |
|||
payload#1 |
|||
payload#2 |
|||
payload#3 |
|||
payload#4 |
|||
payload#1 |
|||
payload#5 |
|||
(".p) -. <S:0 TASK NB. unused payloads |
|||
┌─────────┬─────────┐ |
|||
│payload#0│payload#6│ |
|||
└─────────┴─────────┘ |
|||
TASK |
|||
┌───────────────────────────────────────────────────────────────────┐ |
|||
│┌─────────────────────────────────────────────────────────────────┐│ |
|||
││┌─────────────────────┬───────────────────────────────┬─────────┐││ |
|||
│││┌─────────┬─────────┐│┌─────────┬─────────┬─────────┐│payload#5│││ |
|||
││││payload#1│payload#2│││payload#3│payload#4│payload#1││ │││ |
|||
│││└─────────┴─────────┘│└─────────┴─────────┴─────────┘│ │││ |
|||
││└─────────────────────┴───────────────────────────────┴─────────┘││ |
|||
│└─────────────────────────────────────────────────────────────────┘│ |
|||
└───────────────────────────────────────────────────────────────────┘ |
|||
{:: TASK NB. map |
|||
┌─────────────────────────────────────────────────────┐ |
|||
│┌───────────────────────────────────────────────────┐│ |
|||
││┌─────────────────┬─────────────────────────┬─────┐││ |
|||
│││┌───────┬───────┐│┌───────┬───────┬───────┐│┌┬┬─┐│││ |
|||
││││┌┬┬─┬─┐│┌┬┬─┬─┐│││┌┬┬─┬─┐│┌┬┬─┬─┐│┌┬┬─┬─┐│││││2││││ |
|||
│││││││0│0│││││0│1│││││││1│0│││││1│1│││││1│2│││└┴┴─┘│││ |
|||
││││└┴┴─┴─┘│└┴┴─┴─┘│││└┴┴─┴─┘│└┴┴─┴─┘│└┴┴─┴─┘││ │││ |
|||
│││└───────┴───────┘│└───────┴───────┴───────┘│ │││ |
|||
││└─────────────────┴─────────────────────────┴─────┘││ |
|||
│└───────────────────────────────────────────────────┘│ |
|||
└─────────────────────────────────────────────────────┘ |
|||
(0; 0; 0; 0) {:: TASK NB. indexing |
|||
payload#1 |
|||
(0;0;2){::TASK |
|||
payload#5 |
|||
</pre> |
|||
===Gerund representation=== |
|||
<pre> |
|||
NB. finally, look at the representation of the substitution gerund |
|||
({.@:[)`(I.@:(= {:)~)`] |
|||
┌───────────┬──────────────────────────┬─┐ |
|||
│┌──┬──────┐│┌─┬──────────────────────┐│]│ |
|||
││@:│┌──┬─┐│││~│┌────────────────────┐││ │ |
|||
││ ││{.│[││││ ││┌──┬───────────────┐│││ │ |
|||
││ │└──┴─┘│││ │││@:│┌──┬──────────┐││││ │ |
|||
│└──┴──────┘││ │││ ││I.│┌─┬──────┐│││││ │ |
|||
│ ││ │││ ││ ││2│┌─┬──┐││││││ │ |
|||
│ ││ │││ ││ ││ ││=│{:│││││││ │ |
|||
│ ││ │││ ││ ││ │└─┴──┘││││││ │ |
|||
│ ││ │││ ││ │└─┴──────┘│││││ │ |
|||
│ ││ │││ │└──┴──────────┘││││ │ |
|||
│ ││ ││└──┴───────────────┘│││ │ |
|||
│ ││ │└────────────────────┘││ │ |
|||
│ │└─┴──────────────────────┘│ │ |
|||
└───────────┴──────────────────────────┴─┘ |
|||
</pre> |
|||
=={{header|jq}}== |
|||
In this entry, we suppose that both the template and the payload are provided externally, both |
|||
because that is normally how programs of the type under consideration are used, and because it is consistent with a "separation of concerns" principle. To keep things simple, let's put everything into a bash script. |
|||
For the main task, the key ideas here are (1) to use a JSON dictionary to store the integer-to-payload mapping; and (2) to use the built-in filter, `walk/1`, to instantiate the template. |
|||
<syntaxhighlight lang="sh"> |
|||
#!/bin/bash |
|||
function template { |
|||
cat<<EOF |
|||
[ |
|||
[[1, 2], |
|||
[3, 4, 1], |
|||
5 ]] |
|||
EOF |
|||
} |
|||
function payload { |
|||
for i in $(seq 0 6) ; do |
|||
echo Payload#$i |
|||
done |
|||
} |
|||
# Task 1: Template instantiation |
|||
payload | jq -Rn --argfile t <(template) ' |
|||
([inputs] | with_entries(.key |= tostring)) as $dict |
|||
| $t |
|||
| walk(if type == "number" then $dict[tostring] else . end) |
|||
' |
|||
</syntaxhighlight> |
|||
This produces the expected output, as also shown below. |
|||
For the second task, we could separately invoke jq similarly: |
|||
<syntaxhighlight lang="sh"> |
|||
payload | jq -Rn --argfile t <(template) ' |
|||
([inputs] | with_entries(.key |= tostring)) as $dict |
|||
| $dict[(($dict|keys_unsorted) - ([ $t | .. | numbers ] | unique | map(tostring) ))[]] |
|||
' |
|||
</syntaxhighlight> |
|||
Or, if you prefer one invocation of jq for both tasks:<syntaxhighlight lang="sh"> |
|||
payload | jq -Rrn --argfile t <(template) ' |
|||
([inputs] | with_entries(.key |= tostring)) as $dict |
|||
| $t |
|||
| walk(if type == "number" then $dict[tostring] else . end), |
|||
"\nUnused payload", |
|||
$dict[(($dict|keys_unsorted) - ([ $t | .. | numbers ] | unique | map(tostring) ))[]] |
|||
'</syntaxhighlight> |
|||
{{out}} |
|||
<syntaxhighlight lang="sh">[ |
|||
[ |
|||
[ |
|||
"Payload#1", |
|||
"Payload#2" |
|||
], |
|||
[ |
|||
"Payload#3", |
|||
"Payload#4", |
|||
"Payload#1" |
|||
], |
|||
"Payload#5" |
|||
] |
|||
] |
|||
Unused payload |
|||
Payload#0 |
|||
Payload#6</syntaxhighlight> |
|||
=={{header|Julia}}== |
=={{header|Julia}}== |
||
The array structure needs to be specified as Any type of data, to allow |
The array structure needs to be specified as Any type of data, to allow assignment of String to positions in the array originally containing integers. |
||
< |
<syntaxhighlight lang="julia">t = ([Any[Any[1, 2], |
||
Any[3, 4, 1], |
Any[3, 4, 1], |
||
5]]) |
5]]) |
||
Line 187: | Line 1,006: | ||
show(t) |
show(t) |
||
</ |
</syntaxhighlight>{{output}}<pre> |
||
Array{Any,1}[[Any["Payload#1", "Payload#2"], Any["Payload#3", "Payload#4", "Payload#1"], "Payload#5"]] |
Array{Any,1}[[Any["Payload#1", "Payload#2"], Any["Payload#3", "Payload#4", "Payload#1"], "Payload#5"]] |
||
</pre> |
</pre> |
||
=={{header| |
=={{header|Mathematica}}/{{header|Wolfram Language}}== |
||
<syntaxhighlight lang="mathematica">t = ToExpression[StringReplace["[[[1,2],[3,4,1],5]]", {"[" -> "{", "]" -> "}"}]]; |
|||
p = "Payload#" <> ToString[#] & /@ Range[6]; |
|||
Map[p[[#]] &, t, {-1}]</syntaxhighlight> |
|||
{{out}} |
|||
<pre>{{{"Payload#1", "Payload#2"}, {"Payload#3", "Payload#4", "Payload#1"}, "Payload#5"}}</pre> |
|||
<lang M2000 Interpreter> |
|||
=={{header|M2000 Interpreter}}== |
|||
Font "Courier New" |
|||
<syntaxhighlight lang="m2000 interpreter">Font "Courier New" |
|||
cls |
cls |
||
Module Checkit { |
Module Checkit { |
||
Line 340: | Line 1,165: | ||
} |
} |
||
Checkit |
Checkit |
||
Report clipboard$ |
Report clipboard$</syntaxhighlight> |
||
</lang> |
|||
{{out}} |
{{out}} |
||
<pre style="height:30ex;overflow:scroll"> |
<pre style="height:30ex;overflow:scroll">Payloads: |
||
Payloads: |
|||
Payload#0 |
Payload#0 |
||
Payload#1 |
Payload#1 |
||
Line 385: | Line 1,208: | ||
Missing in position: |
Missing in position: |
||
Payload#10-pos2 |
Payload#10-pos2 |
||
Payload#16-pos5 |
Payload#16-pos5</pre> |
||
</pre > |
|||
=={{header|Nim}}== |
|||
<syntaxhighlight lang="nim">import macros,sugar,strformat |
|||
#macro to take a nested tuple and return a type |
|||
#e.g. (int,(int,int))=>(string,(string,string)) |
|||
proc intstr(n: NimNode): NimNode = |
|||
if n.kind == nnkSym: |
|||
return ident("string") |
|||
result = nnkPar.newNimNode() |
|||
for i in 1..<n.len: |
|||
result.add(intstr(n[i])) |
|||
macro tuptype(t: typed): untyped = intstr(t.getType) |
|||
proc replace(t: tuple | int, p: openArray[string]): auto = |
|||
when t is int: (if t in 0..<p.len: p[t] else: "nil") |
|||
else: |
|||
var res: tuptype(t) |
|||
for k, v in t.fieldpairs: |
|||
#k will be 'Field0', so we convert to an integer index |
|||
res[k[^1].int - '0'.int] = replace(v, p) |
|||
return res |
|||
when isMainModule: |
|||
let p = collect(for i in 0..5: &"payload{i}") |
|||
let tplt1 = ((1,2),(3,4,1),5) |
|||
let tplt2 = ((1,2),(3,4,1),6) |
|||
echo replace(tplt1, p) |
|||
echo replace(tplt2, p)</syntaxhighlight> |
|||
{{out}} |
|||
<pre>(("payload1", "payload2"), ("payload3", "payload4", "payload1"), "payload5") |
|||
(("payload1", "payload2"), ("payload3", "payload4", "payload1"), "nil")</pre> |
|||
=={{header|Perl}}== |
=={{header|Perl}}== |
||
Only handles nesting one level deep. Missing data is <code>undef</code> in the data structure, an empty string in the pretty-printer. |
Only handles nesting one level deep. Missing data is <code>undef</code> in the data structure, an empty string in the pretty-printer. |
||
< |
<syntaxhighlight lang="perl">sub fulfill { |
||
my @payloads; |
my @payloads; |
||
push @payloads, 'Payload#' . $_ for 0..5; |
push @payloads, 'Payload#' . $_ for 0..5; |
||
Line 406: | Line 1,261: | ||
print formatted fulfill( [[1,2], [ 3,4,1], 5] ); |
print formatted fulfill( [[1,2], [ 3,4,1], 5] ); |
||
print formatted fulfill( [[1,2], [10,4,1], 5] ); |
print formatted fulfill( [[1,2], [10,4,1], 5] ); |
||
</syntaxhighlight> |
|||
</lang> |
|||
{{out}} |
{{out}} |
||
<pre>[ [ "Payload#1", "Payload#2" ], [ "Payload#3", "Payload#4", "Payload#1" ], "Payload#5" ] |
<pre>[ [ "Payload#1", "Payload#2" ], [ "Payload#3", "Payload#4", "Payload#1" ], "Payload#5" ] |
||
[ [ "Payload#1", "Payload#2" ], [ "", "Payload#4", "Payload#1" ], "Payload#5" ]</pre> |
[ [ "Payload#1", "Payload#2" ], [ "", "Payload#4", "Payload#1" ], "Payload#5" ]</pre> |
||
===Arbitrary Nesting=== |
|||
=={{header|Perl 6}}== |
|||
<syntaxhighlight lang="perl">#!/usr/bin/perl |
|||
{{works with|Rakudo|2018.04.01}} |
|||
Explicitly not using strings, using one data structure to fill in another. Since it ''isn't'' a string, the output format removes the newlines from the template; line feed (white space in general) isn't particularly significant in Perl 6 data structures. It does preserve the nesting though. In the second example, payload "buckets" that don't exist result in an undefined value being inserted; by default: Any. |
|||
<lang perl6>say join "\n ", '##PAYLOADS:', |my @payloads = 'Payload#' X~ ^7; |
|||
use strict; # https://rosettacode.org/wiki/Nested_templated_data |
|||
for [ |
|||
use warnings; |
|||
(((1, 2), |
|||
use Data::Dump 'dd'; |
|||
(3, 4, 1), |
|||
5),), |
|||
my $t = [ |
|||
(((1, 2), |
|||
[[1, 2], |
|||
[3, 4, 1], |
|||
5]]; |
|||
say "\n Template: ", $_.perl; |
|||
my $p = [ map "Payload#$_", 0 .. 6 ]; |
|||
say "Data structure: { @payloads[|$_].perl }"; |
|||
dd { 'template' => $t, 'payload' => $p }; |
|||
}</lang> |
|||
{{out}} |
|||
<pre>##PAYLOADS: |
|||
Payload#0 |
|||
Payload#1 |
|||
Payload#2 |
|||
Payload#3 |
|||
Payload#4 |
|||
Payload#5 |
|||
Payload#6 |
|||
my $output = filltemplate( $t, $p ); |
|||
Template: $(((1, 2), (3, 4, 1), 5),) |
|||
dd { 'output' => $output }; |
|||
Data structure: ((("Payload#1", "Payload#2"), ("Payload#3", "Payload#4", "Payload#1"), "Payload#5"),) |
|||
sub filltemplate |
|||
Template: $(((1, 2), (10, 4, 1), 5),) |
|||
{ |
|||
Data structure: ((("Payload#1", "Payload#2"), (Any, "Payload#4", "Payload#1"), "Payload#5"),)</pre> |
|||
my ($t, $p) = @_; |
|||
return ref $t eq 'ARRAY' ? [ map filltemplate($_, $p), @$t ] : $p->[$t]; |
|||
}</syntaxhighlight> |
|||
{{out}} |
|||
<pre> |
|||
{ |
|||
payload => [ |
|||
"Payload#0", |
|||
"Payload#1", |
|||
"Payload#2", |
|||
"Payload#3", |
|||
"Payload#4", |
|||
"Payload#5", |
|||
"Payload#6", |
|||
], |
|||
template => [[[1, 2], [3, 4, 1], 5]], |
|||
} |
|||
{ |
|||
output => [ |
|||
[ |
|||
["Payload#1", "Payload#2"], |
|||
["Payload#3", "Payload#4", "Payload#1"], |
|||
"Payload#5", |
|||
], |
|||
], |
|||
} |
|||
</pre> |
|||
=={{header|Phix}}== |
=={{header|Phix}}== |
||
Line 448: | Line 1,318: | ||
Note that Phix indexes are normally 1-based, but to better match the task description those in the templates are 0-based |
Note that Phix indexes are normally 1-based, but to better match the task description those in the templates are 0-based |
||
<!--<syntaxhighlight lang="phix">(phixonline)--> |
|||
<lang Phix>constant template = { { { 1, 2 }, { 3, 4, 1, }, 5 } }, |
|||
<span style="color: #008080;">constant</span> <span style="color: #000000;">template</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">{</span> <span style="color: #0000FF;">{</span> <span style="color: #0000FF;">{</span> <span style="color: #000000;">1</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">2</span> <span style="color: #0000FF;">},</span> <span style="color: #0000FF;">{</span> <span style="color: #000000;">3</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">4</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">1</span><span style="color: #0000FF;">,</span> <span style="color: #0000FF;">},</span> <span style="color: #000000;">5</span> <span style="color: #0000FF;">}</span> <span style="color: #0000FF;">},</span> |
|||
template2 = { { { 1, 2 }, { 10, 4, 1 }, 5 } }, |
|||
<span style="color: #000000;">template2</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">{</span> <span style="color: #0000FF;">{</span> <span style="color: #0000FF;">{</span> <span style="color: #000000;">1</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">2</span> <span style="color: #0000FF;">},</span> <span style="color: #0000FF;">{</span> <span style="color: #000000;">10</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">4</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">1</span> <span style="color: #0000FF;">},</span> <span style="color: #000000;">5</span> <span style="color: #0000FF;">}</span> <span style="color: #0000FF;">},</span> |
|||
payload = {"Payload#0", "Payload#1", "Payload#2", "Payload#3", "Payload#4", "Payload#5", "Payload#6"} |
|||
<span style="color: #000000;">payload</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">{</span><span style="color: #008000;">"Payload#0"</span><span style="color: #0000FF;">,</span> <span style="color: #008000;">"Payload#1"</span><span style="color: #0000FF;">,</span> <span style="color: #008000;">"Payload#2"</span><span style="color: #0000FF;">,</span> <span style="color: #008000;">"Payload#3"</span><span style="color: #0000FF;">,</span> <span style="color: #008000;">"Payload#4"</span><span style="color: #0000FF;">,</span> <span style="color: #008000;">"Payload#5"</span><span style="color: #0000FF;">,</span> <span style="color: #008000;">"Payload#6"</span><span style="color: #0000FF;">}</span> |
|||
sequence unused = repeat(true,length(payload)), |
|||
<span style="color: #004080;">sequence</span> <span style="color: #000000;">unused</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">repeat</span><span style="color: #0000FF;">(</span><span style="color: #004600;">true</span><span style="color: #0000FF;">,</span><span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">payload</span><span style="color: #0000FF;">)),</span> |
|||
missing = {} |
|||
<span style="color: #000000;">missing</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">{}</span> |
|||
function fill(object t, sequence p) |
|||
<span style="color: #008080;">function</span> <span style="color: #000000;">fill</span><span style="color: #0000FF;">(</span><span style="color: #004080;">object</span> <span style="color: #000000;">t</span><span style="color: #0000FF;">,</span> <span style="color: #004080;">sequence</span> <span style="color: #000000;">p</span><span style="color: #0000FF;">)</span> |
|||
if integer(t) then |
|||
<span style="color: #008080;">if</span> <span style="color: #004080;">integer</span><span style="color: #0000FF;">(</span><span style="color: #000000;">t</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">then</span> |
|||
if t>=length(p) then |
|||
<span style="color: #008080;">if</span> <span style="color: #000000;">t</span><span style="color: #0000FF;">>=</span><span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">p</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">then</span> |
|||
if not find(t,missing) then missing &= t end if |
|||
<span style="color: #008080;">if</span> <span style="color: #008080;">not</span> <span style="color: #7060A8;">find</span><span style="color: #0000FF;">(</span><span style="color: #000000;">t</span><span style="color: #0000FF;">,</span><span style="color: #000000;">missing</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">then</span> <span style="color: #000000;">missing</span> <span style="color: #0000FF;">&=</span> <span style="color: #000000;">t</span> <span style="color: #008080;">end</span> <span style="color: #008080;">if</span> |
|||
return sprintf("*** index error (%d>%d) ***",{t,length(p)-1}) |
|||
<span style="color: #008080;">return</span> <span style="color: #7060A8;">sprintf</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"*** index error (%d>%d) ***"</span><span style="color: #0000FF;">,{</span><span style="color: #000000;">t</span><span style="color: #0000FF;">,</span><span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">p</span><span style="color: #0000FF;">)-</span><span style="color: #000000;">1</span><span style="color: #0000FF;">})</span> |
|||
end if |
|||
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span> |
|||
unused[t+1] = false |
|||
<span style="color: #000000;">unused</span><span style="color: #0000FF;">[</span><span style="color: #000000;">t</span><span style="color: #0000FF;">+</span><span style="color: #000000;">1</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">=</span> <span style="color: #004600;">false</span> |
|||
return p[t+1] |
|||
<span style="color: #008080;">return</span> <span style="color: #000000;">p</span><span style="color: #0000FF;">[</span><span style="color: #000000;">t</span><span style="color: #0000FF;">+</span><span style="color: #000000;">1</span><span style="color: #0000FF;">]</span> |
|||
end if |
|||
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span> |
|||
for i=1 to length(t) do |
|||
<span style="color: #008080;">for</span> <span style="color: #000000;">i</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">t</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">do</span> |
|||
t[i] = fill(t[i],p) |
|||
<span style="color: #000000;">t</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">fill</span><span style="color: #0000FF;">(</span><span style="color: #000000;">t</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">],</span><span style="color: #000000;">p</span><span style="color: #0000FF;">)</span> |
|||
end for |
|||
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span> |
|||
return t |
|||
<span style="color: #008080;">return</span> <span style="color: #000000;">t</span> |
|||
end function |
|||
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span> |
|||
ppOpt({pp_Nest,2}) |
|||
<span style="color: #7060A8;">ppOpt</span><span style="color: #0000FF;">({</span><span style="color: #004600;">pp_Nest</span><span style="color: #0000FF;">,</span><span style="color: #000000;">2</span><span style="color: #0000FF;">})</span> |
|||
pp(fill(template,payload)) |
|||
<span style="color: #7060A8;">pp</span><span style="color: #0000FF;">(</span><span style="color: #000000;">fill</span><span style="color: #0000FF;">(</span><span style="color: #000000;">template</span><span style="color: #0000FF;">,</span><span style="color: #000000;">payload</span><span style="color: #0000FF;">))</span> |
|||
pp(fill(template2,payload)) |
|||
<span style="color: #7060A8;">pp</span><span style="color: #0000FF;">(</span><span style="color: #000000;">fill</span><span style="color: #0000FF;">(</span><span style="color: #000000;">template2</span><span style="color: #0000FF;">,</span><span style="color: #000000;">payload</span><span style="color: #0000FF;">))</span> |
|||
sequence idx = {} |
|||
<span style="color: #004080;">sequence</span> <span style="color: #000000;">idx</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">{}</span> |
|||
for i=1 to length(unused) do |
|||
<span style="color: #008080;">for</span> <span style="color: #000000;">i</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">unused</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">do</span> |
|||
if unused[i] then idx &= i-1 end if |
|||
<span style="color: #008080;">if</span> <span style="color: #000000;">unused</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">]</span> <span style="color: #008080;">then</span> <span style="color: #000000;">idx</span> <span style="color: #0000FF;">&=</span> <span style="color: #000000;">i</span><span style="color: #0000FF;">-</span><span style="color: #000000;">1</span> <span style="color: #008080;">end</span> <span style="color: #008080;">if</span> |
|||
end for |
|||
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span> |
|||
printf(1,"\nThe unused payloads have indices of :%s\n", {sprint(idx)}) |
|||
<span style="color: #7060A8;">printf</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"\nThe unused payloads have indices of :%s\n"</span><span style="color: #0000FF;">,</span> <span style="color: #0000FF;">{</span><span style="color: #7060A8;">sprint</span><span style="color: #0000FF;">(</span><span style="color: #000000;">idx</span><span style="color: #0000FF;">)})</span> |
|||
if length(missing) then |
|||
<span style="color: #008080;">if</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">missing</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">then</span> |
|||
printf(1,"Missing payloads: %s\n", {sprint(missing)}) |
|||
<span style="color: #7060A8;">printf</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"Missing payloads: %s\n"</span><span style="color: #0000FF;">,</span> <span style="color: #0000FF;">{</span><span style="color: #7060A8;">sprint</span><span style="color: #0000FF;">(</span><span style="color: #000000;">missing</span><span style="color: #0000FF;">)})</span> |
|||
end if</lang> |
|||
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span> |
|||
<!--</syntaxhighlight>--> |
|||
<pre> |
<pre> |
||
{{{"Payload#1", "Payload#2"}, |
{{{"Payload#1", "Payload#2"}, |
||
Line 500: | Line 1,372: | ||
A distinctive string is used to indicate missing payloads. |
A distinctive string is used to indicate missing payloads. |
||
< |
<syntaxhighlight lang="python">from pprint import pprint as pp |
||
class Template(): |
class Template(): |
||
Line 548: | Line 1,420: | ||
print(" MISSING PAYLOADS:\n ", end='') |
print(" MISSING PAYLOADS:\n ", end='') |
||
missed = t.missed_payloads |
missed = t.missed_payloads |
||
print('\n '.join(missed) if missed else '-')</ |
print('\n '.join(missed) if missed else '-')</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
Line 594: | Line 1,466: | ||
MISSING PAYLOADS: |
MISSING PAYLOADS: |
||
??#10</pre> |
??#10</pre> |
||
=={{header|R}}== |
|||
This is a fairly straightforward implementation in R using a recursive function. It's not likely the most efficient in the world. |
|||
<syntaxhighlight lang="r">fill_template <- function(x, template, prefix = "Payload#") { |
|||
for (i in seq_along(template)) { |
|||
temp_slice <- template[[i]] |
|||
if (is.list(temp_slice)) { |
|||
template[[i]] <- fill_template(x, temp_slice, prefix) |
|||
} else { |
|||
temp_slice <- paste0(prefix, temp_slice) |
|||
template[[i]] <- x[match(temp_slice, x)] |
|||
} |
|||
} |
|||
return(template) |
|||
} |
|||
library("jsonlite") # for printing the template and result |
|||
template <- list(list(c(1, 2), c(3, 4), 5)) |
|||
payload <- paste0("Payload#", 0:6) |
|||
result <- fill_template(payload, template) |
|||
cat(sprintf( |
|||
"Template\t%s\nPayload\t%s\nResult\t%s", |
|||
toJSON(template, auto_unbox = TRUE), |
|||
toJSON(payload, auto_unbox = TRUE), |
|||
toJSON(result, auto_unbox = TRUE) |
|||
))</syntaxhighlight> |
|||
{{out}} |
|||
<pre>Template [[[1,2],[3,4],5]] |
|||
Payload ["Payload#0","Payload#1","Payload#2","Payload#3","Payload#4","Payload#5","Payload#6"] |
|||
Result [[["Payload#1","Payload#2"],["Payload#3","Payload#4"],"Payload#5"]]</pre> |
|||
=={{header|Racket}}== |
=={{header|Racket}}== |
||
Line 599: | Line 1,506: | ||
<code>rackunit</code> is used to test the outcomes of template application. So no output indicates expectations met (i.e. success). |
<code>rackunit</code> is used to test the outcomes of template application. So no output indicates expectations met (i.e. success). |
||
< |
<syntaxhighlight lang="racket">#lang racket |
||
(define current-not-found-handler |
(define current-not-found-handler |
||
Line 631: | Line 1,538: | ||
(parameterize ((current-not-found-handler (λ (idx max) (format "?~a" idx)))) |
(parameterize ((current-not-found-handler (λ (idx max) (format "?~a" idx)))) |
||
(check-equal? (out-of-bounds-generating-template-substitution p) '("?7"))))</ |
(check-equal? (out-of-bounds-generating-template-substitution p) '("?7"))))</syntaxhighlight> |
||
=={{header|Raku}}== |
|||
(formerly Perl 6) |
|||
{{works with|Rakudo|2020.08.1}} |
|||
Explicitly not using strings, using one data structure to fill in another. Since it ''isn't'' a string, the output format removes the newlines from the template; line feed (white space in general) isn't particularly significant in Raku data structures. It does preserve the nesting though. In the second example, payload "buckets" that don't exist result in an undefined value being inserted; by default: Any. |
|||
<syntaxhighlight lang="raku" line>say join "\n ", '##PAYLOADS:', |my @payloads = 'Payload#' X~ ^7; |
|||
for [ |
|||
(((1, 2), |
|||
(3, 4, 1), |
|||
5),), |
|||
(((1, 2), |
|||
(10, 4, 1), |
|||
5),) |
|||
] { |
|||
say "\n Template: ", $_.raku; |
|||
say "Data structure: { @payloads[|$_].raku }"; |
|||
}</syntaxhighlight> |
|||
{{out}} |
|||
<pre>##PAYLOADS: |
|||
Payload#0 |
|||
Payload#1 |
|||
Payload#2 |
|||
Payload#3 |
|||
Payload#4 |
|||
Payload#5 |
|||
Payload#6 |
|||
Template: $(((1, 2), (3, 4, 1), 5),) |
|||
Data structure: ((("Payload#1", "Payload#2"), ("Payload#3", "Payload#4", "Payload#1"), "Payload#5"),) |
|||
Template: $(((1, 2), (10, 4, 1), 5),) |
|||
Data structure: ((("Payload#1", "Payload#2"), (Any, "Payload#4", "Payload#1"), "Payload#5"),)</pre> |
|||
=={{header|Refal}}== |
|||
<syntaxhighlight lang="refal">$ENTRY Go { |
|||
, (((1 2) (3 4 1) 5)): e.Template |
|||
, "Payload#0" "Payload#1" "Payload#2" "Payload#3" |
|||
"Payload#4" "Payload#5" "Payload#6": e.Payload |
|||
= <Prout <Subst (e.Payload) e.Template>>; |
|||
}; |
|||
Subst { |
|||
(e.P) = ; |
|||
(e.P) s.I e.X = <Item s.I e.P> <Subst (e.P) e.X>; |
|||
(e.P) (e.X) e.Y = (<Subst (e.P) e.X>) <Subst (e.P) e.Y>; |
|||
}; |
|||
Item { |
|||
0 t.I e.X = t.I; |
|||
s.N t.I e.X = <Item <- s.N 1> e.X>; |
|||
};</syntaxhighlight> |
|||
{{out}} |
|||
<pre>(((Payload#1 Payload#2 )(Payload#3 Payload#4 Payload#1 )Payload#5 ))</pre> |
|||
=={{header|REXX}}== |
=={{header|REXX}}== |
||
===version 1=== |
===version 1=== |
||
< |
<syntaxhighlight lang="rexx">/* REXX */ |
||
tok.='' |
tok.='' |
||
Do i=0 To 6 |
Do i=0 To 6 |
||
Line 740: | Line 1,701: | ||
End |
End |
||
Else |
Else |
||
Return "'Payload#" i "not defined'"</ |
Return "'Payload#" i "not defined'"</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
<pre>Template [[[1,2],[3,4,1],5]] |
<pre>Template [[[1,2],[3,4,1],5]] |
||
Line 756: | Line 1,717: | ||
===version 2=== |
===version 2=== |
||
< |
<syntaxhighlight lang="rexx">/* REXX */ |
||
tok.='' |
tok.='' |
||
Do i=0 To 6 |
Do i=0 To 6 |
||
Line 855: | Line 1,816: | ||
o: Say arg(1) |
o: Say arg(1) |
||
Return</ |
Return</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
<pre>[[[1,2],[ 3,4,1],5]] |
<pre>[[[1,2],[ 3,4,1],5]] |
||
Line 881: | Line 1,842: | ||
Payload 9 is not defined |
Payload 9 is not defined |
||
Payload 8 is not defined</pre> |
Payload 8 is not defined</pre> |
||
=={{header|SETL}}== |
|||
<syntaxhighlight lang="setl">program substitution; |
|||
template := [[[1,2],[3,4,1],5]]; |
|||
payload := { |
|||
[0,"Payload#0"], [1,"Payload#1"], [2,"Payload#2"], [3,"Payload#3"], |
|||
[4,"Payload#4"], [5,"Payload#5"], [6,"Payload#6"] |
|||
}; |
|||
print(subst(template, payload)); |
|||
proc subst(template, payload); |
|||
if not is_tuple(template) then |
|||
return(payload(template)); |
|||
end if; |
|||
result := []; |
|||
loop for item in template do |
|||
result with:= subst(item, payload); |
|||
end loop; |
|||
return result; |
|||
end proc; |
|||
end program;</syntaxhighlight> |
|||
{{out}} |
|||
<pre>[[['Payload#1' 'Payload#2'] ['Payload#3' 'Payload#4' 'Payload#1'] 'Payload#5']]</pre> |
|||
=={{header|VBA}}== |
|||
VBA allows arrays of variant, so the elements of an array can be both scalars as arrays of different sizes. |
|||
<syntaxhighlight lang="vb">Public Sub test() |
|||
Dim t(2) As Variant |
|||
t(0) = [{1,2}] |
|||
t(1) = [{3,4,1}] |
|||
t(2) = 5 |
|||
p = [{"Payload#0","Payload#1","Payload#2","Payload#3","Payload#4","Payload#5","Payload#6"}] |
|||
Dim q(6) As Boolean |
|||
For i = LBound(t) To UBound(t) |
|||
If IsArray(t(i)) Then |
|||
For j = LBound(t(i)) To UBound(t(i)) |
|||
q(t(i)(j)) = True |
|||
t(i)(j) = p(t(i)(j) + 1) |
|||
Next j |
|||
Else |
|||
q(t(i)) = True |
|||
t(i) = p(t(i) + 1) |
|||
End If |
|||
Next i |
|||
For i = LBound(t) To UBound(t) |
|||
If IsArray(t(i)) Then |
|||
Debug.Print Join(t(i), ", ") |
|||
Else |
|||
Debug.Print t(i) |
|||
End If |
|||
Next i |
|||
For i = LBound(q) To UBound(q) |
|||
If Not q(i) Then Debug.Print p(i + 1); " is not used" |
|||
Next i |
|||
End Sub</syntaxhighlight>{{out}} |
|||
<pre>Payload#1, Payload#2 |
|||
Payload#3, Payload#4, Payload#1 |
|||
Payload#5 |
|||
Payload#0 is not used |
|||
Payload#6 is not used</pre> |
|||
=={{header|Wren}}== |
|||
{{trans|Crystal}} |
|||
{{libheader|Wren-set}} |
|||
{{libheader|Wren-sort}} |
|||
<syntaxhighlight lang="wren">import "./set" for Set |
|||
import "./sort" for Sort |
|||
var withPayload // recursive function |
|||
withPayload = Fn.new { |template, payload, used| |
|||
return template.map { |item| |
|||
if (item is List) { |
|||
return withPayload.call(item, payload, used) |
|||
} else { |
|||
used.add(item) |
|||
return "'%(payload[item])'" |
|||
} |
|||
}.toList |
|||
} |
|||
var p = ["Payload#0", "Payload#1", "Payload#2", "Payload#3", "Payload#4", "Payload#5", "Payload#6"] |
|||
var t = [[[1, 2], [3, 4, 1], 5]] |
|||
var used = [] |
|||
System.print(withPayload.call(t, p, used)) |
|||
System.print() |
|||
var unused = Set.new(0..6).except(Set.new(used)).toList |
|||
Sort.insertion(unused) |
|||
System.print("The unused payloads have indices of %(unused).")</syntaxhighlight> |
|||
{{out}} |
|||
<pre> |
|||
[[['Payload#1', 'Payload#2'], ['Payload#3', 'Payload#4', 'Payload#1'], 'Payload#5']] |
|||
The unused payloads have indices of [0, 6]. |
|||
</pre> |
|||
=={{header|zkl}}== |
=={{header|zkl}}== |
||
Line 887: | Line 1,944: | ||
Void is used as a marker for an unknown payload. |
Void is used as a marker for an unknown payload. |
||
< |
<syntaxhighlight lang="zkl">var payloads=[1..6].pump(List,"Payload#".append); |
||
fcn get(n){ try{ payloads[n - 1] }catch{ Void } } |
fcn get(n){ try{ payloads[n - 1] }catch{ Void } } |
||
fcn sub(list){ list.pump(List, fcn(n){ if(n.isType(List)) sub(n) else get(n) }) }</ |
fcn sub(list){ list.pump(List, fcn(n){ if(n.isType(List)) sub(n) else get(n) }) }</syntaxhighlight> |
||
< |
<syntaxhighlight lang="zkl">foreach p in (T( |
||
T(T(T(1, 2), |
T(T(T(1, 2), |
||
T(3, 4, 1), |
T(3, 4, 1), |
||
Line 899: | Line 1,956: | ||
5),))){ |
5),))){ |
||
println(" Template: %s\nData structure: %s".fmt(p,sub(p))); |
println(" Template: %s\nData structure: %s".fmt(p,sub(p))); |
||
}</ |
}</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
<pre> |
<pre> |
Latest revision as of 07:34, 3 May 2024
You are encouraged to solve this task according to the task description, using any language you may know.
A template for data is an arbitrarily nested tree of integer indices.
Data payloads are given as a separate mapping, array or other simpler, flat,
association of indices to individual items of data, and are strings.
The idea is to create a data structure with the templates' nesting, and the
payload corresponding to each index appearing at the position of each index.
Answers using simple string replacement or regexp are to be avoided. The idea is to use the native, or usual implementation of lists/tuples etc of the language and to hierarchically traverse the template to generate the output.
- Task Detail
Given the following input template t
and list of payloads p
:
# Square brackets are used here to denote nesting but may be changed for other,
# clear, visual representations of nested data appropriate to ones programming
# language.
t = [
[[1, 2],
[3, 4, 1],
5]]
p = 'Payload#0' ... 'Payload#6'
The correct output should have the following structure, (although spacing and linefeeds may differ, the nesting and order should follow):
[[['Payload#1', 'Payload#2'],
['Payload#3', 'Payload#4', 'Payload#1'],
'Payload#5']]
1. Generate the output for the above template, t
.
- Optional Extended tasks
2. Show which payloads remain unused.
3. Give some indication/handling of indices without a payload.
Show output on this page.
AutoHotkey
;-----------------------------------------------------------
Nested_templated_data(template, Payload){
UsedP := [], UnusedP := [], UnusedI := []
result := template.Clone()
x := ArrMap(template, Payload, result, UsedP, UnusedI, [])
for i, v in Payload
if !UsedP[v]
UnusedP.Push(v)
return [x.1, x.2, UnusedP]
}
;-----------------------------------------------------------
ArrMap(Template, Payload, result, UsedP, UnusedI, pth){
for i, index in Template {
if IsObject(index)
pth.Push(i), Arrmap(index, Payload, result, UsedP, UnusedI, pth)
else{
pth.Push(i), ArrSetPath(result, pth, Payload[index])
if Payload[index]
UsedP[Payload[index]] := 1
else
UnusedI.Push(index)
}
pth.Pop()
}
return [result, UnusedI, UsedP]
}
;-----------------------------------------------------------
ArrSetPath(Arr, pth, newVal){
temp := []
for k, v in pth{
temp.push(v)
if !IsObject(Arr[temp*])
Arr[temp*] := []
}
return Arr[temp*] := newVal
}
;-----------------------------------------------------------
objcopy(obj){
nobj := obj.Clone()
for k, v in nobj
if IsObject(v)
nobj[k] := objcopy(v)
return nobj
}
;-----------------------------------------------------------
Examples:
T := [[[1,2] , [3,4,1] , 5]]
; Autohotkey uses 1-based objects/arrays
P := ["Payload#1", "Payload#2", "Payload#3", "Payload#4", "Payload#5", "Payload#6", "Payload#7"]
Results := Nested_templated_data(objcopy(t), P)
output := Results.1
Undefined_indices := Results[2]
Unused_Payloads := Results[3]
- Output:
T := [[[1,2] , [3,4,1] , 5]] P := ["Payload#1", "Payload#2", "Payload#3", "Payload#4", "Payload#5", "Payload#6", "Payload#7"] output : [[["payload#1", "payload#2"] , ["payload#3", "payload#4", "payload#1"] , "payload#5"]] Undefined_indices : [] Unused_Payloads : ["Payload#6", "Payload#7"] ;----------------------------------------------------------- T := [[[1,2] , [3,4,1,8] , 5]] P := ["Payload#1", "Payload#2", "Payload#3", "Payload#4", "Payload#5", "Payload#6", "Payload#7"] output : [[["payload#1", "payload#2"] , ["payload#3", "payload#4", "payload#1", ""] , "payload#5"]] Undefined_indices : [8] Unused_Payloads : ["Payload#6", "Payload#7"]
BASIC
Applesoft BASIC
The GW-BASIC solution works without any changes.
BASIC256
dim p(7)
dim p$(7)
p$[0] = "Payload#0" : p$[1] = "Payload#1"
p$[2] = "Payload#2" : p$[3] = "Payload#3"
p$[4] = "Payload#4" : p$[5] = "Payload#5"
p$[6] = "Payload#6"
dim q(7) fill false
dim t(4, 5)
t[0, 0] = 1: t[0, 1] = 2
t[1, 0] = 3: t[1, 1] = 4: t[1, 2] = 1
t[2, 0] = 5
for i = 0 to t[?][]-1
for j = 0 to t[?][]-1
if t[i, j] <> 0 then
q[t[i, j]] = true
t[i, j] += 1
end if
next j
next i
for i = 0 to t[?][]-1
for j = 0 to t[?][]-1
if t[i, j] <> 0 then print p$[t[i, j] -1]; " ";
next j
print
next i
for i = 0 to q[?]-1
if not q[i] then print p$[i]; " is not used"
next i
- Output:
Same as FreeBASIC entry.
Chipmunk Basic
100 cls
110 dim i,j,p(6)
120 dim p$(6)
130 p$(0) = "Payload#0" : p$(1) = "Payload#1"
140 p$(2) = "Payload#2" : p$(3) = "Payload#3"
150 p$(4) = "Payload#4" : p$(5) = "Payload#5"
160 p$(6) = "Payload#6"
170 dim q(6)
180 dim t(2,3)
190 t(0,0) = 1 : t(0,1) = 2
200 t(1,0) = 3 : t(1,1) = 4 : t(1,2) = 1
210 t(2,0) = 5
220 for i = 0 to ubound(t)
230 for j = 0 to ubound(t,2)
240 if t(i,j) <> 0 then
250 q(t(i,j)) = true
260 t(i,j) = t(i,j)+1
270 endif
280 next j
290 next i
300 for i = 0 to ubound(t)
310 for j = 0 to ubound(t,2)
320 if t(i,j) <> 0 then print p$(t(i,j)-1);" ";
330 next j
340 print
350 next i
360 for i = 0 to ubound(q)
370 if not q(i) then print p$(i);" is not used"
380 next i
390 end
- Output:
Same as FreeBASIC entry.
FreeBASIC
Dim As Integer t(2, 3) = {{1,2},{3,4,1},{5}}
Dim As Integer i, j, p(6)
Dim As String pStr(6) = {"Payload#0", "Payload#1", "Payload#2", "Payload#3", "Payload#4", "Payload#5", "Payload#6"}
Dim As Boolean q(6)
For i = Lbound(t) To Ubound(t)
For j = Lbound(t, 2) To Ubound(t, 2)
If t(i, j) <> 0 Then
q(t(i, j)) = True
t(i, j) += 1
End If
Next j
Next i
For i = Lbound(t) To Ubound(t)
For j = Lbound(t, 2) To Ubound(t, 2)
If t(i, j) <> 0 Then Print pStr(t(i, j)-1); " ";
Next j
Print
Next i
For i = Lbound(q) To Ubound(q)
If q(i) = False Then Print pStr(i); " is not used"
Next i
Sleep
- Output:
Payload#1 Payload#2 Payload#3 Payload#4 Payload#1 Payload#5 Payload#0 is not used Payload#6 is not used
GW-BASIC
110 TRUE = -1
120 FALSE = NOT TRUE
130 DIM I,J,P(6)
140 DIM P$(6)
150 P$(0) = "Payload#0" : P$(1) = "Payload#1"
160 P$(2) = "Payload#2" : P$(3) = "Payload#3"
170 P$(4) = "Payload#4" : P$(5) = "Payload#5"
180 P$(6) = "Payload#6"
190 DIM Q(6)
200 DIM T(2,3)
210 T(0,0) = 1 : T(0,1) = 2
220 T(1,0) = 3 : T(1,1) = 4 : T(1,2) = 1
230 T(2,0) = 5
240 FOR I = 0 TO 2
250 FOR J = 0 TO 3
260 IF T(I,J) <> 0 THEN Q(T(I,J)) = TRUE : T(I,J) = T(I,J)+1
270 NEXT J
280 NEXT I
290 FOR I = 0 TO 2
300 FOR J = 0 TO 3
310 IF T(I,J) <> 0 THEN PRINT P$(T(I,J)-1);" ";
320 NEXT J
330 PRINT
340 NEXT I
350 FOR I = 0 TO 6
360 IF Q(I) = FALSE THEN PRINT P$(I);" is not used"
370 NEXT I
380 END
- Output:
Same as FreeBASIC entry.
MSX Basic
The GW-BASIC solution works without any changes.
QBasic
True = -1: False = NOT True
DIM p(6)
DIM p$(6)
p$(0) = "Payload#0": p$(1) = "Payload#1"
p$(2) = "Payload#2": p$(3) = "Payload#3"
p$(4) = "Payload#4": p$(5) = "Payload#5"
p$(6) = "Payload#6"
DIM q(6)
DIM t(2, 3)
t(0, 0) = 1: t(0, 1) = 2
t(1, 0) = 3: t(1, 1) = 4: t(1, 2) = 1
t(2, 0) = 5
FOR i = LBOUND(t) TO UBOUND(t) '0 To 2
FOR j = LBOUND(t, 2) TO UBOUND(t, 2) '0 To 3
IF t(i, j) <> 0 THEN
q(t(i, j)) = True
t(i, j) = t(i, j) + 1
END IF
NEXT j
NEXT i
FOR i = LBOUND(t) TO UBOUND(t) '0 To 2
FOR j = LBOUND(t, 2) TO UBOUND(t, 2) '0 To 3
IF t(i, j) <> 0 THEN PRINT p$(t(i, j) - 1); " ";
NEXT j
PRINT
NEXT i
FOR i = LBOUND(q) TO UBOUND(q)
IF q(i) = False THEN PRINT p$(i); " is not used"
NEXT i
- Output:
Same as FreeBASIC entry.
QB64
The QBasic solution works without any changes.
Run BASIC
DIM p(6)
DIM p$(6)
p$(0) = "Payload#0": p$(1) = "Payload#1"
p$(2) = "Payload#2": p$(3) = "Payload#3"
p$(4) = "Payload#4": p$(5) = "Payload#5"
p$(6) = "Payload#6"
DIM q(6)
DIM t(2, 3)
t(0, 0) = 1: t(0, 1) = 2
t(1, 0) = 3: t(1, 1) = 4: t(1, 2) = 1
t(2, 0) = 5
FOR i = 0 TO 2
FOR j = 0 TO 3
IF t(i, j) <> 0 THEN
q(t(i, j)) = -1
t(i, j) = t(i, j) + 1
END IF
NEXT j
NEXT i
FOR i = 0 TO 2
FOR j = 0 TO 3
IF t(i, j) <> 0 THEN PRINT p$(t(i, j) - 1); " ";
NEXT j
PRINT
NEXT i
FOR i = 0 TO 6
IF q(i) = 0 THEN PRINT p$(i); " is not used"
NEXT i
- Output:
Same as QBasic entry.
Yabasic
dim p(6)
dim p$(6)
p$(0) = "Payload#0" : p$(1) = "Payload#1"
p$(2) = "Payload#2" : p$(3) = "Payload#3"
p$(4) = "Payload#4" : p$(5) = "Payload#5"
p$(6) = "Payload#6"
dim q(6)
dim t(2, 3)
t(0, 0) = 1: t(0, 1) = 2
t(1, 0) = 3: t(1, 1) = 4: t(1, 2) = 1
t(2, 0) = 5
for i = 0 to arraysize(t(), 1)
for j = 0 to arraysize(t(), 2)
if t(i, j) <> 0 then
q(t(i, j)) = True
t(i, j) = t(i, j) + 1
fi
next j
next i
for i = 0 to arraysize(t(), 1)
for j = 0 to arraysize(t(), 2)
if t(i, j) <> 0 print p$(t(i, j) -1), " ";
next j
print
next i
for i = 0 to arraysize(q(), 1)
if not q(i) print p$(i), " is not used"
next i
- Output:
Same as FreeBASIC entry.
Bracmat
The uninstantiated template and the instantiated template are JSON structures. The payloads are listed in a Bracmat list. The get
function is instructed to read input from memory and to parse it as JSON. The output of this call is a Bracmat structure (not shown) that is assigned to template
. The instantiate
function recursively traverses the template's tree structure. If the current node is a number, then that number is used as the key into the payloads list. The corresponding payload is then returned. If the current node is not a number, then it is assumed that the current node is a binary (sub)tree. The left hand side (called a
) and the right hand side (called b
) are instantiated and their combination is returned. Finally the instantiated tree is transformed back to JSON format and output.
( get$("[
[[1, 2],
[3, 4, 1],
5]]",MEM,JSN)
: ?template
& (0.payload#0)
(1.payload#1)
(2.payload#2)
(3.payload#3)
(4.payload#4)
(5.payload#5)
(6.payload#6)
: ?payloads
& ( instantiate
= tmplt plds pld a b
. !arg:(?tmplt.?plds)
& ( !tmplt:#
& !plds:? (!tmplt.?pld) ?
& !pld
| !tmplt:%?a_%?b
& (instantiate$(!a.!plds))_(instantiate$(!b.!plds))
)
)
& out$(jsn$(instantiate$(!template.!payloads)))
);
- Output:
[[[payload#1,payload#2],[payload#3,payload#4,payload#1],payload#5]]
C++
Uses C++17 or later.
The nested indexes are defined by tuples from the standard library. C++ function templates recursively traverse the tuple structure and map to the payloads.
#include <iostream>
#include <set>
#include <tuple>
#include <vector>
using namespace std;
// print a single payload
template<typename P>
void PrintPayloads(const P &payloads, int index, bool isLast)
{
if(index < 0 || index >= (int)size(payloads)) cout << "null";
else cout << "'" << payloads[index] << "'";
if (!isLast) cout << ", "; // add a comma between elements
}
// print a tuple of playloads
template<typename P, typename... Ts>
void PrintPayloads(const P &payloads, tuple<Ts...> const& nestedTuple, bool isLast = true)
{
std::apply // recursively call PrintPayloads on each element of the tuple
(
[&payloads, isLast](Ts const&... tupleArgs)
{
size_t n{0};
cout << "[";
(PrintPayloads(payloads, tupleArgs, (++n == sizeof...(Ts)) ), ...);
cout << "]";
cout << (isLast ? "\n" : ",\n");
}, nestedTuple
);
}
// find the unique index of a single index (helper for the function below)
void FindUniqueIndexes(set<int> &indexes, int index)
{
indexes.insert(index);
}
// find the unique indexes in the tuples
template<typename... Ts>
void FindUniqueIndexes(set<int> &indexes, std::tuple<Ts...> const& nestedTuple)
{
std::apply
(
[&indexes](Ts const&... tupleArgs)
{
(FindUniqueIndexes(indexes, tupleArgs),...);
}, nestedTuple
);
}
// print the payloads that were not used
template<typename P>
void PrintUnusedPayloads(const set<int> &usedIndexes, const P &payloads)
{
for(size_t i = 0; i < size(payloads); i++)
{
if(usedIndexes.find(i) == usedIndexes.end() ) cout << payloads[i] << "\n";
}
}
int main()
{
// define the playloads, they can be in most containers
vector payloads {"Payload#0", "Payload#1", "Payload#2", "Payload#3", "Payload#4", "Payload#5", "Payload#6"};
const char *shortPayloads[] {"Payload#0", "Payload#1", "Payload#2", "Payload#3"}; // as a C array
// define the indexes as a nested tuple
auto tpl = make_tuple(make_tuple(
make_tuple(1, 2),
make_tuple(3, 4, 1),
5));
cout << "Mapping indexes to payloads:\n";
PrintPayloads(payloads, tpl);
cout << "\nFinding unused payloads:\n";
set<int> usedIndexes;
FindUniqueIndexes(usedIndexes, tpl);
PrintUnusedPayloads(usedIndexes, payloads);
cout << "\nMapping to some out of range payloads:\n";
PrintPayloads(shortPayloads, tpl);
return 0;
}
- Output:
Mapping indexes to payloads: [[['Payload#1', 'Payload#2'], ['Payload#3', 'Payload#4', 'Payload#1'], 'Payload#5'] ] Finding unused payloads: Payload#0 Payload#6 Mapping to some out of range payloads: [[['Payload#1', 'Payload#2'], ['Payload#3', null, 'Payload#1'], null] ]
Crystal
def with_payload(template, payload, used = nil)
template.map do |item|
if item.is_a? Enumerable
with_payload(item, payload, used)
else
used << item
payload[item]
end
end
end
p = {"Payload#0", "Payload#1", "Payload#2", "Payload#3", "Payload#4", "Payload#5", "Payload#6"}
t = { { {1, 2}, {3, 4, 1}, 5}}
used = Set(Int32).new
puts with_payload(t, p, used)
unused = Set(Int32).new((0..6).to_a) - used
puts "Unused indices: #{unused}"
- Output:
{{{"Payload#1", "Payload#2"}, {"Payload#3", "Payload#4", "Payload#1"}, "Payload#5"}} Unused indices: Set{0, 6}
Factor
Words for traversing nested sequences can be found in the sequences.deep
vocabulary. Factor's prettyprinter attempts to print structures on a single line (64 characters by default, though this can be changed) if they will fit. Otherwise, the prettyprinter will break them up into multiple lines, preferring to show one member per line if possible. f
, Factor's false/nil value, is used to indicate a missing payload.
USING: formatting kernel literals math sequences sequences.deep ;
IN: rosetta-code.nested-template-data
CONSTANT: payloads $[ 7 <iota> [ "Payload#%d" sprintf ] map ]
: insert-payloads ( template -- data-structure )
[ dup fixnum? [ payloads ?nth ] when ] deep-map ;
{ { { 1 2 }
{ 3 4 1 }
5 } }
{ { { 1 2 }
{ 10 4 1 }
5 } }
[ dup insert-payloads "Template: %u\nData Structure: %u\n"
printf ] bi@
- Output:
Template: { { { 1 2 } { 3 4 1 } 5 } } Data Structure: { { { "Payload#1" "Payload#2" } { "Payload#3" "Payload#4" "Payload#1" } "Payload#5" } } Template: { { { 1 2 } { 10 4 1 } 5 } } Data Structure: { { { "Payload#1" "Payload#2" } { f "Payload#4" "Payload#1" } "Payload#5" } }
Go
Go's standard library includes a "text/template" package which can be used for this task.
The integer indices are represented by the keys of a map whose corresponding value is the appropriate payload string. Templates have their own mini-language and, for a map P with key n, the expression:
{{index .P n}}
will be replaced by the corresponding payload.
If an integer index either doesn't exist in the map or maps to an empty payload, then the above expression will simply be replaced by an empty string when the template is executed.
package main
import (
"fmt"
"os"
"sort"
"strings"
"text/template"
)
func main() {
const t = `[[[{{index .P 1}}, {{index .P 2}}],
[{{index .P 3}}, {{index .P 4}}, {{index .P 1}}],
{{index .P 5}}]]
`
type S struct {
P map[int]string
}
var s S
s.P = map[int]string{
0: "'Payload#0'", 1: "'Payload#1'", 2: "'Payload#2'", 3: "'Payload#3'",
4: "'Payload#4'", 5: "'Payload#5'", 6: "'Payload#6'",
}
tmpl := template.Must(template.New("").Parse(t))
tmpl.Execute(os.Stdout, s)
var unused []int
for k, _ := range s.P {
if !strings.Contains(t, fmt.Sprintf("{{index .P %d}}", k)) {
unused = append(unused, k)
}
}
sort.Ints(unused)
fmt.Println("\nThe unused payloads have indices of :", unused)
}
- Output:
[[['Payload#1', 'Payload#2'], ['Payload#3', 'Payload#4', 'Payload#1'], 'Payload#5']] The unused payloads have indices of : [0 6]
Haskell
The problem is ideal for demonstrating the Functor and Traversable concepts.
Being a functor allows changing the contents of a complex data structure, keeping structure unchanged (via fmap function). This property already matches the template idea, but we can go further. The structure may be foldable as well, allowing aggregation of contents, using arbitrary monoid or aggregating function. Moreover foldable functor may be traversable, giving the ability to modify the complex structure contents with computations held in a given applicative or monadic context. All these properties are well defined, have solid theoretical background and are presented by classes: Functor, Foldable and Traversable.
For wide class of data structures instances of all these classes may be derived by the compiler in a sound unique way. The data template given in the task is exactly the case of a functor.
If we do not bother about neat textual representation, the definition of traversable nested template is as easy as following:
{-# language DeriveTraversable #-}
data Template a = Val a | List [Template a]
deriving ( Show
, Functor
, Foldable
, Traversable )
Functorial property of a data type is sufficient for defining the universal substitutor of keys/indices by payload data:
subst :: (Functor t, Eq i) => [(i,a)] -> t i -> t (Maybe a)
subst d = fmap (`lookup` d)
It is possible to turn any list of payloads into a map by simple helper function:
indexed :: [a] -> [(Int, a)]
indexed = zip [0..]
Now we can make substitutions to flat lists or nested templates:
t :: Template Int
t = List [ List [Val 1, Val 2]
, List [Val 3, Val 4, Val 10]
, Val 5]
payloads :: [(Int, String)]
payloads = [(i, "payload#"++show i) | i <- [0..6]]
λ> subst payloads [6,2,1,2] [Just "payload#6",Just "payload#2",Just "payload#1",Just "payload#2"] λ> sequence $ subst payloads [6,2,1,2] Just ["payload#6","payload#2","payload#1","payload#2"] λ> indexed "traverse" [(0,'t'),(1,'r'),(2,'a'),(3,'v'),(4,'e'),(5,'r'),(6,'s'),(7,'e')] λ> subst (indexed "traverse") [6,7,1,3,4,1] [Just 's',Just 'e',Just 'r',Just 'v',Just 'e',Just 'r'] λ> sequence . subst (indexed "traverse") [6,7,1,3,4,1] Just "server" λ> subst payloads t List [ List [Val (Just "payload#1"),Val (Just "payload#2")] , List [Val (Just "payload#3"),Val (Just "payload#4"),Val Nothing] , Val (Just "payload#5")] λ> sequence $ subst payloads t Nothing
In the last case not all substitutions could be done, so the whole substitution failed. The sequence function works for any traversable structures.
Foldable properties of templates (with a little help of monoids) allow to implement extended tasks.
unusedIndices :: (Foldable t, Eq i) => [(i,a)] -> t i -> [i]
unusedIndices d = foldMap unused
where unused i = maybe (pure i) (pure []) $ lookup i d
unusedData :: (Foldable t, Eq i) => [(i, a)] -> t i -> [(i,a)]
unusedData = foldr delete
where delete i = filter ((i /= ) . fst)
λ> unusedIndices payloads t [10] λ> unusedData payloads t [(0,"payload#0"),(6,"payload#6")]
J
Group substitution
Substitute=: ({.@:[)`(I.@:(= {:)~)`]} NB. aside: demonstrate Substitution ] A =: ;/ i. 8 ┌─┬─┬─┬─┬─┬─┬─┬─┐ │0│1│2│3│4│5│6│7│ └─┴─┴─┴─┴─┴─┴─┴─┘ ] B =: ('xxxx' ; 3) ┌────┬─┐ │xxxx│3│ └────┴─┘ B Substitute A ┌─┬─┬─┬────┬─┬─┬─┬─┐ │0│1│2│xxxx│4│5│6│7│ └─┴─┴─┴────┴─┴─┴─┴─┘ B Substitute A , < 3 ┌─┬─┬─┬────┬─┬─┬─┬─┬────┐ │0│1│2│xxxx│4│5│6│7│xxxx│ └─┴─┴─┴────┴─┴─┴─┴─┴────┘
Convert template to j structured data
NB. algorithm: evaluate after rewrite as a j sentence NB. the result is an actual structured noun. NB. because arrays are homogeneous in data type NB. 1) data type validity for an operation takes place just once for all the values in the array which is fast NB. 2) but a box next to a 5 is invalid. NB. hence the payloads must be individually boxed as well. ] p =: ('(<''payload#',''')',~":)&>i.7 (<'payload#0') (<'payload#1') (<'payload#2') (<'payload#3') (<'payload#4') (<'payload#5') (<'payload#6') NB. though they look scalar the words are vector ] t =: ;: CRLF -.~ 0 :0 [ [[1, 2], [3, 4, 1], 5]] ) ┌─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┐ │[│[│[│1│,│2│]│,│[│3│,│4│,│1│]│,│5│]│]│ └─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┘ t =: ,: t NB. itemize t, then append successive substitutions t =: t , ('(<' ; , '[') Substitute {: t t =: t , ( ')' ; , ']') Substitute {: t t ┌──┬──┬──┬─┬─┬─┬─┬─┬──┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┐ │[ │[ │[ │1│,│2│]│,│[ │3│,│4│,│1│]│,│5│]│]│ ├──┼──┼──┼─┼─┼─┼─┼─┼──┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┤ │(<│(<│(<│1│,│2│]│,│(<│3│,│4│,│1│]│,│5│]│]│ ├──┼──┼──┼─┼─┼─┼─┼─┼──┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┤ │(<│(<│(<│1│,│2│)│,│(<│3│,│4│,│1│)│,│5│)│)│ └──┴──┴──┴─┴─┴─┴─┴─┴──┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┘ NB. finish the substitutions in one fell swoop ] SUBSTITUTIONS=: (<"1 p) ,. ,@":&.> i.7 ┌──────────────┬─┐ │(<'payload#0')│0│ ├──────────────┼─┤ │(<'payload#1')│1│ ├──────────────┼─┤ │(<'payload#2')│2│ ├──────────────┼─┤ │(<'payload#3')│3│ ├──────────────┼─┤ │(<'payload#4')│4│ ├──────────────┼─┤ │(<'payload#5')│5│ ├──────────────┼─┤ │(<'payload#6')│6│ └──────────────┴─┘ [ t =: > (] , (Substitute {:))&.>/(<"1 SUBSTITUTIONS) , < t ┌──┬──┬──┬──────────────┬─┬──────────────┬─┬─┬──┬──────────────┬─┬──────────────┬─┬──────────────┬─┬─┬──────────────┬─┬─┐ │[ │[ │[ │1 │,│2 │]│,│[ │3 │,│4 │,│1 │]│,│5 │]│]│ ├──┼──┼──┼──────────────┼─┼──────────────┼─┼─┼──┼──────────────┼─┼──────────────┼─┼──────────────┼─┼─┼──────────────┼─┼─┤ │(<│(<│(<│1 │,│2 │]│,│(<│3 │,│4 │,│1 │]│,│5 │]│]│ ├──┼──┼──┼──────────────┼─┼──────────────┼─┼─┼──┼──────────────┼─┼──────────────┼─┼──────────────┼─┼─┼──────────────┼─┼─┤ │(<│(<│(<│1 │,│2 │)│,│(<│3 │,│4 │,│1 │)│,│5 │)│)│ ├──┼──┼──┼──────────────┼─┼──────────────┼─┼─┼──┼──────────────┼─┼──────────────┼─┼──────────────┼─┼─┼──────────────┼─┼─┤ │(<│(<│(<│1 │,│2 │)│,│(<│3 │,│4 │,│1 │)│,│5 │)│)│ ├──┼──┼──┼──────────────┼─┼──────────────┼─┼─┼──┼──────────────┼─┼──────────────┼─┼──────────────┼─┼─┼──────────────┼─┼─┤ │(<│(<│(<│1 │,│2 │)│,│(<│3 │,│4 │,│1 │)│,│(<'payload#5')│)│)│ ├──┼──┼──┼──────────────┼─┼──────────────┼─┼─┼──┼──────────────┼─┼──────────────┼─┼──────────────┼─┼─┼──────────────┼─┼─┤ │(<│(<│(<│1 │,│2 │)│,│(<│3 │,│(<'payload#4')│,│1 │)│,│(<'payload#5')│)│)│ ├──┼──┼──┼──────────────┼─┼──────────────┼─┼─┼──┼──────────────┼─┼──────────────┼─┼──────────────┼─┼─┼──────────────┼─┼─┤ │(<│(<│(<│1 │,│2 │)│,│(<│(<'payload#3')│,│(<'payload#4')│,│1 │)│,│(<'payload#5')│)│)│ ├──┼──┼──┼──────────────┼─┼──────────────┼─┼─┼──┼──────────────┼─┼──────────────┼─┼──────────────┼─┼─┼──────────────┼─┼─┤ │(<│(<│(<│1 │,│(<'payload#2')│)│,│(<│(<'payload#3')│,│(<'payload#4')│,│1 │)│,│(<'payload#5')│)│)│ ├──┼──┼──┼──────────────┼─┼──────────────┼─┼─┼──┼──────────────┼─┼──────────────┼─┼──────────────┼─┼─┼──────────────┼─┼─┤ │(<│(<│(<│(<'payload#1')│,│(<'payload#2')│)│,│(<│(<'payload#3')│,│(<'payload#4')│,│(<'payload#1')│)│,│(<'payload#5')│)│)│ ├──┼──┼──┼──────────────┼─┼──────────────┼─┼─┼──┼──────────────┼─┼──────────────┼─┼──────────────┼─┼─┼──────────────┼─┼─┤ │(<│(<│(<│(<'payload#1')│,│(<'payload#2')│)│,│(<│(<'payload#3')│,│(<'payload#4')│,│(<'payload#1')│)│,│(<'payload#5')│)│)│ └──┴──┴──┴──────────────┴─┴──────────────┴─┴─┴──┴──────────────┴─┴──────────────┴─┴──────────────┴─┴─┴──────────────┴─┴─┘ ] TASK=: ". ;:inv {: t NB. task output ┌───────────────────────────────────────────────────────────────────┐ │┌─────────────────────────────────────────────────────────────────┐│ ││┌─────────────────────┬───────────────────────────────┬─────────┐││ │││┌─────────┬─────────┐│┌─────────┬─────────┬─────────┐│payload#5│││ ││││payload#1│payload#2│││payload#3│payload#4│payload#1││ │││ │││└─────────┴─────────┘│└─────────┴─────────┴─────────┘│ │││ ││└─────────────────────┴───────────────────────────────┴─────────┘││ │└─────────────────────────────────────────────────────────────────┘│ └───────────────────────────────────────────────────────────────────┘
Explorations
L. TASK NB. level 4 <S:1 TASK NB. spread boxing at level 1 ┌─────────────────────┬───────────────────────────────┬─────────┐ │┌─────────┬─────────┐│┌─────────┬─────────┬─────────┐│payload#5│ ││payload#1│payload#2│││payload#3│payload#4│payload#1││ │ │└─────────┴─────────┘│└─────────┴─────────┴─────────┘│ │ └─────────────────────┴───────────────────────────────┴─────────┘ [S:0 TASK NB. leaves payload#1 payload#2 payload#3 payload#4 payload#1 payload#5 (".p) -. <S:0 TASK NB. unused payloads ┌─────────┬─────────┐ │payload#0│payload#6│ └─────────┴─────────┘ TASK ┌───────────────────────────────────────────────────────────────────┐ │┌─────────────────────────────────────────────────────────────────┐│ ││┌─────────────────────┬───────────────────────────────┬─────────┐││ │││┌─────────┬─────────┐│┌─────────┬─────────┬─────────┐│payload#5│││ ││││payload#1│payload#2│││payload#3│payload#4│payload#1││ │││ │││└─────────┴─────────┘│└─────────┴─────────┴─────────┘│ │││ ││└─────────────────────┴───────────────────────────────┴─────────┘││ │└─────────────────────────────────────────────────────────────────┘│ └───────────────────────────────────────────────────────────────────┘ {:: TASK NB. map ┌─────────────────────────────────────────────────────┐ │┌───────────────────────────────────────────────────┐│ ││┌─────────────────┬─────────────────────────┬─────┐││ │││┌───────┬───────┐│┌───────┬───────┬───────┐│┌┬┬─┐│││ ││││┌┬┬─┬─┐│┌┬┬─┬─┐│││┌┬┬─┬─┐│┌┬┬─┬─┐│┌┬┬─┬─┐│││││2││││ │││││││0│0│││││0│1│││││││1│0│││││1│1│││││1│2│││└┴┴─┘│││ ││││└┴┴─┴─┘│└┴┴─┴─┘│││└┴┴─┴─┘│└┴┴─┴─┘│└┴┴─┴─┘││ │││ │││└───────┴───────┘│└───────┴───────┴───────┘│ │││ ││└─────────────────┴─────────────────────────┴─────┘││ │└───────────────────────────────────────────────────┘│ └─────────────────────────────────────────────────────┘ (0; 0; 0; 0) {:: TASK NB. indexing payload#1 (0;0;2){::TASK payload#5
Gerund representation
NB. finally, look at the representation of the substitution gerund ({.@:[)`(I.@:(= {:)~)`] ┌───────────┬──────────────────────────┬─┐ │┌──┬──────┐│┌─┬──────────────────────┐│]│ ││@:│┌──┬─┐│││~│┌────────────────────┐││ │ ││ ││{.│[││││ ││┌──┬───────────────┐│││ │ ││ │└──┴─┘│││ │││@:│┌──┬──────────┐││││ │ │└──┴──────┘││ │││ ││I.│┌─┬──────┐│││││ │ │ ││ │││ ││ ││2│┌─┬──┐││││││ │ │ ││ │││ ││ ││ ││=│{:│││││││ │ │ ││ │││ ││ ││ │└─┴──┘││││││ │ │ ││ │││ ││ │└─┴──────┘│││││ │ │ ││ │││ │└──┴──────────┘││││ │ │ ││ ││└──┴───────────────┘│││ │ │ ││ │└────────────────────┘││ │ │ │└─┴──────────────────────┘│ │ └───────────┴──────────────────────────┴─┘
jq
In this entry, we suppose that both the template and the payload are provided externally, both because that is normally how programs of the type under consideration are used, and because it is consistent with a "separation of concerns" principle. To keep things simple, let's put everything into a bash script.
For the main task, the key ideas here are (1) to use a JSON dictionary to store the integer-to-payload mapping; and (2) to use the built-in filter, `walk/1`, to instantiate the template.
#!/bin/bash
function template {
cat<<EOF
[
[[1, 2],
[3, 4, 1],
5 ]]
EOF
}
function payload {
for i in $(seq 0 6) ; do
echo Payload#$i
done
}
# Task 1: Template instantiation
payload | jq -Rn --argfile t <(template) '
([inputs] | with_entries(.key |= tostring)) as $dict
| $t
| walk(if type == "number" then $dict[tostring] else . end)
'
This produces the expected output, as also shown below.
For the second task, we could separately invoke jq similarly:
payload | jq -Rn --argfile t <(template) '
([inputs] | with_entries(.key |= tostring)) as $dict
| $dict[(($dict|keys_unsorted) - ([ $t | .. | numbers ] | unique | map(tostring) ))[]]
'
Or, if you prefer one invocation of jq for both tasks:
payload | jq -Rrn --argfile t <(template) '
([inputs] | with_entries(.key |= tostring)) as $dict
| $t
| walk(if type == "number" then $dict[tostring] else . end),
"\nUnused payload",
$dict[(($dict|keys_unsorted) - ([ $t | .. | numbers ] | unique | map(tostring) ))[]]
'
- Output:
[
[
[
"Payload#1",
"Payload#2"
],
[
"Payload#3",
"Payload#4",
"Payload#1"
],
"Payload#5"
]
]
Unused payload
Payload#0
Payload#6
Julia
The array structure needs to be specified as Any type of data, to allow assignment of String to positions in the array originally containing integers.
t = ([Any[Any[1, 2],
Any[3, 4, 1],
5]])
p = ["Payload#$x" for x in 0:6]
for (i, e) in enumerate(t)
if e isa Number
t[i] = p[e + 1]
else
for (j, f) in enumerate(e)
if f isa Number
e[j] = p[f + 1]
else
for (k, g) in enumerate(f)
if g isa Number
f[k] = p[g + 1]
end
end
end
end
end
end
show(t)
- Output:
Array{Any,1}[[Any["Payload#1", "Payload#2"], Any["Payload#3", "Payload#4", "Payload#1"], "Payload#5"]]
Mathematica/Wolfram Language
t = ToExpression[StringReplace["[[[1,2],[3,4,1],5]]", {"[" -> "{", "]" -> "}"}]];
p = "Payload#" <> ToString[#] & /@ Range[6];
Map[p[[#]] &, t, {-1}]
- Output:
{{{"Payload#1", "Payload#2"}, {"Payload#3", "Payload#4", "Payload#1"}, "Payload#5"}}
M2000 Interpreter
Font "Courier New"
cls
Module Checkit {
t=(((1,2), (3,4,1),5),) ' use (1,) for one item tuple
Tuple$ = lambda$ (a, feed$=" ") -> {
\\ we can pass a tuple of two arguments or two arguments
k=each(a)
lim=len(a)-1
res$="("
link a to a() ' to use type$()
while k {
if type$(a(k^))="mArray" then
res$+=Lambda$(array(a, k^),feed$+" ")
if k^<lim then
res$+={,
}+feed$
end if
else
res$+= trim$(str$(array(k)))
if k^<lim then res$+=", "
end if
}
=res$+")"
}
TotalPayload = lambda (a)->{
k=each(a)
link a to a()
res=0
while k {
if type$(a(k^))="mArray" then
res+=Lambda(a(k^))
else
res++
end if
}
=res
}
Payload = lambda (a,payloads as list)->{
misspayloads=List
used=list
inner=lambda misspayloads, p=1, payloads, used (a)-> {
k=each(a)
res=(,)
link a to a()
while k {
if type$(a(k^))="mArray" then
Append res, (Lambda(a(k^)),)
else
curpayload$="Payload#"+trim$(str$(array(k)))
if not exist(payloads, curpayload$) Then
if not exist(used, curpayload$) Then
Append res, ("missing#pos"+trim$(str$(p)),)
append misspayloads, p:=curpayload$
else
Append res, (curpayload$,)
End if
p++
else
Append res, (curpayload$,)
if exist(payloads, curpayload$) then
delete payloads, curpayload$
if not exist(used, curpayload$) then append used, curpayload$
end if
p++
end if
end if
}
=res
}
=inner(a), payloads, misspayloads
}
Expand$ =lambda$ (a as array, unused as list, misspayloads as list)-> {
Read ? space$
inner$= lambda$ (a, feed$=" ")->{
k=each(a)
lim=len(a)-1
res$="["
link a to a() ' to use type$()
while k {
if type$(a(k^))="mArray" then
res$+=Lambda$(array(a, k^),feed$+" ")
if k^<lim then
res$+={,
}+feed$
end if
else
res$+= "'"+array$(k)+"'"
if k^<lim then res$+=", "
end if
}
=res$+"]"
}
document unused$="Unused Payloads"+{
}
if len(unused)>0 then
un=each(unused)
while un {
unused$=" "+eval$(un)+{
}
}
else
unused$=" -"
end if
if len(misspayloads)>0 then
un=each(misspayloads)
lim=len(misspayloads)-1
document missing$="Missing in position: "+{
}
while un {
missing$=" "+eval$(un)+"-pos"+eval$(un,un^)+{
}
}
=inner$(a, space$)+{
}+unused$+missing$
Else
=inner$(a, space$)+{
} + unused$
End if
}
flush
Data t, (((1,10), (3,4,16),5),)
While not empty {
Read t
Document result$="Payloads:"+{
}
p=list
for i=0 to 6 {
Append p, "Payload#"+trim$(str$(i))
result$=" "+eval$(p, i)+{
}
}
result$="Template:"+{
}
result$=" "+Tuple$(t, " ")+{
}
result$="Template with Payloads:"+{
}
m=Payload(t, p)
result$=" "+Expand$(!m, " ")
clipboard result$
}
}
Checkit
Report clipboard$
- Output:
Payloads: Payload#0 Payload#1 Payload#2 Payload#3 Payload#4 Payload#5 Payload#6 Template: (((1, 2), (3, 4, 1), 5)) Template with Payloads: [[['Payload#1', 'Payload#2'], ['Payload#3', 'Payload#4', 'Payload#1'], 'Payload#5']] Unused Payloads Payload#0 Payload#6 Payloads: Payload#0 Payload#1 Payload#2 Payload#3 Payload#4 Payload#5 Payload#6 Template: (((1, 10), (3, 4, 16), 5)) Template with Payloads: [[['Payload#1', 'missing#pos2'], ['Payload#3', 'Payload#4', 'missing#pos5'], 'Payload#5']] Unused Payloads Payload#0 Payload#6 Payload#2 Missing in position: Payload#10-pos2 Payload#16-pos5
Nim
import macros,sugar,strformat
#macro to take a nested tuple and return a type
#e.g. (int,(int,int))=>(string,(string,string))
proc intstr(n: NimNode): NimNode =
if n.kind == nnkSym:
return ident("string")
result = nnkPar.newNimNode()
for i in 1..<n.len:
result.add(intstr(n[i]))
macro tuptype(t: typed): untyped = intstr(t.getType)
proc replace(t: tuple | int, p: openArray[string]): auto =
when t is int: (if t in 0..<p.len: p[t] else: "nil")
else:
var res: tuptype(t)
for k, v in t.fieldpairs:
#k will be 'Field0', so we convert to an integer index
res[k[^1].int - '0'.int] = replace(v, p)
return res
when isMainModule:
let p = collect(for i in 0..5: &"payload{i}")
let tplt1 = ((1,2),(3,4,1),5)
let tplt2 = ((1,2),(3,4,1),6)
echo replace(tplt1, p)
echo replace(tplt2, p)
- Output:
(("payload1", "payload2"), ("payload3", "payload4", "payload1"), "payload5") (("payload1", "payload2"), ("payload3", "payload4", "payload1"), "nil")
Perl
Only handles nesting one level deep. Missing data is undef
in the data structure, an empty string in the pretty-printer.
sub fulfill {
my @payloads;
push @payloads, 'Payload#' . $_ for 0..5;
my @result;
push @result, ref $_ eq 'ARRAY' ? [@payloads[@$_]] : @payloads[$_] for @{@_[0]};
return [@result];
}
sub formatted {
my $result;
$result .= ref $_ eq 'ARRAY' ? '[ "'. join('", "', @$_) . '" ], ' : qq{"$_"} for @{@_[0]};
return '[ ' . $result . " ]\n";
}
print formatted fulfill( [[1,2], [ 3,4,1], 5] );
print formatted fulfill( [[1,2], [10,4,1], 5] );
- Output:
[ [ "Payload#1", "Payload#2" ], [ "Payload#3", "Payload#4", "Payload#1" ], "Payload#5" ] [ [ "Payload#1", "Payload#2" ], [ "", "Payload#4", "Payload#1" ], "Payload#5" ]
Arbitrary Nesting
#!/usr/bin/perl
use strict; # https://rosettacode.org/wiki/Nested_templated_data
use warnings;
use Data::Dump 'dd';
my $t = [
[[1, 2],
[3, 4, 1],
5]];
my $p = [ map "Payload#$_", 0 .. 6 ];
dd { 'template' => $t, 'payload' => $p };
my $output = filltemplate( $t, $p );
dd { 'output' => $output };
sub filltemplate
{
my ($t, $p) = @_;
return ref $t eq 'ARRAY' ? [ map filltemplate($_, $p), @$t ] : $p->[$t];
}
- Output:
{ payload => [ "Payload#0", "Payload#1", "Payload#2", "Payload#3", "Payload#4", "Payload#5", "Payload#6", ], template => [[[1, 2], [3, 4, 1], 5]], } { output => [ [ ["Payload#1", "Payload#2"], ["Payload#3", "Payload#4", "Payload#1"], "Payload#5", ], ], }
Phix
This task almost feels custom-built for Phix.
Note that Phix indexes are normally 1-based, but to better match the task description those in the templates are 0-based
constant template = { { { 1, 2 }, { 3, 4, 1, }, 5 } }, template2 = { { { 1, 2 }, { 10, 4, 1 }, 5 } }, payload = {"Payload#0", "Payload#1", "Payload#2", "Payload#3", "Payload#4", "Payload#5", "Payload#6"} sequence unused = repeat(true,length(payload)), missing = {} function fill(object t, sequence p) if integer(t) then if t>=length(p) then if not find(t,missing) then missing &= t end if return sprintf("*** index error (%d>%d) ***",{t,length(p)-1}) end if unused[t+1] = false return p[t+1] end if for i=1 to length(t) do t[i] = fill(t[i],p) end for return t end function ppOpt({pp_Nest,2}) pp(fill(template,payload)) pp(fill(template2,payload)) sequence idx = {} for i=1 to length(unused) do if unused[i] then idx &= i-1 end if end for printf(1,"\nThe unused payloads have indices of :%s\n", {sprint(idx)}) if length(missing) then printf(1,"Missing payloads: %s\n", {sprint(missing)}) end if
{{{"Payload#1", "Payload#2"}, {"Payload#3", "Payload#4", "Payload#1"}, "Payload#5"}} {{{"Payload#1", "Payload#2"}, {"*** index error (10>6) ***", "Payload#4", "Payload#1"}, "Payload#5"}} The unused payloads have indices of :{0,6} Missing payloads: {10}
Python
This uses f-strings from Python3.6+.
I choose to use nested tuples for the template structure, and a dict to map integer indices to corresponding payload strings.
A distinctive string is used to indicate missing payloads.
from pprint import pprint as pp
class Template():
def __init__(self, structure):
self.structure = structure
self.used_payloads, self.missed_payloads = [], []
def inject_payload(self, id2data):
def _inject_payload(substruct, i2d, used, missed):
used.extend(i2d[x] for x in substruct if type(x) is not tuple and x in i2d)
missed.extend(f'??#{x}'
for x in substruct if type(x) is not tuple and x not in i2d)
return tuple(_inject_payload(x, i2d, used, missed)
if type(x) is tuple
else i2d.get(x, f'??#{x}')
for x in substruct)
ans = _inject_payload(self.structure, id2data,
self.used_payloads, self.missed_payloads)
self.unused_payloads = sorted(set(id2data.values())
- set(self.used_payloads))
self.missed_payloads = sorted(set(self.missed_payloads))
return ans
if __name__ == '__main__':
index2data = {p: f'Payload#{p}' for p in range(7)}
print("##PAYLOADS:\n ", end='')
print('\n '.join(list(index2data.values())))
for structure in [
(((1, 2),
(3, 4, 1),
5),),
(((1, 2),
(10, 4, 1),
5),)]:
print("\n\n# TEMPLATE:")
pp(structure, width=13)
print("\n TEMPLATE WITH PAYLOADS:")
t = Template(structure)
out = t.inject_payload(index2data)
pp(out)
print("\n UNUSED PAYLOADS:\n ", end='')
unused = t.unused_payloads
print('\n '.join(unused) if unused else '-')
print(" MISSING PAYLOADS:\n ", end='')
missed = t.missed_payloads
print('\n '.join(missed) if missed else '-')
- Output:
##PAYLOADS: Payload#0 Payload#1 Payload#2 Payload#3 Payload#4 Payload#5 Payload#6 # TEMPLATE: (((1, 2), (3, 4, 1), 5),) TEMPLATE WITH PAYLOADS: ((('Payload#1', 'Payload#2'), ('Payload#3', 'Payload#4', 'Payload#1'), 'Payload#5'),) UNUSED PAYLOADS: Payload#0 Payload#6 MISSING PAYLOADS: - # TEMPLATE: (((1, 2), (10, 4, 1), 5),) TEMPLATE WITH PAYLOADS: ((('Payload#1', 'Payload#2'), ('??#10', 'Payload#4', 'Payload#1'), 'Payload#5'),) UNUSED PAYLOADS: Payload#0 Payload#3 Payload#6 MISSING PAYLOADS: ??#10
R
This is a fairly straightforward implementation in R using a recursive function. It's not likely the most efficient in the world.
fill_template <- function(x, template, prefix = "Payload#") {
for (i in seq_along(template)) {
temp_slice <- template[[i]]
if (is.list(temp_slice)) {
template[[i]] <- fill_template(x, temp_slice, prefix)
} else {
temp_slice <- paste0(prefix, temp_slice)
template[[i]] <- x[match(temp_slice, x)]
}
}
return(template)
}
library("jsonlite") # for printing the template and result
template <- list(list(c(1, 2), c(3, 4), 5))
payload <- paste0("Payload#", 0:6)
result <- fill_template(payload, template)
cat(sprintf(
"Template\t%s\nPayload\t%s\nResult\t%s",
toJSON(template, auto_unbox = TRUE),
toJSON(payload, auto_unbox = TRUE),
toJSON(result, auto_unbox = TRUE)
))
- Output:
Template [[[1,2],[3,4],5]] Payload ["Payload#0","Payload#1","Payload#2","Payload#3","Payload#4","Payload#5","Payload#6"] Result [[["Payload#1","Payload#2"],["Payload#3","Payload#4"],"Payload#5"]]
Racket
rackunit
is used to test the outcomes of template application. So no output indicates expectations met (i.e. success).
#lang racket
(define current-not-found-handler
(make-parameter (λ (idx max) (raise-range-error 'substitute-template "integer?" "" idx 0 max))))
(define ((substitute-template template) payloads)
(define match-function
(match-lambda
[(? nonnegative-integer? idx) #:when (< idx (length payloads)) (list-ref payloads idx)]
[(? nonnegative-integer? idx) ((current-not-found-handler) idx (sub1 (length payloads)))]
[(list (app match-function substitutions) ...) substitutions]))
(match-function template))
(module+ test
(require rackunit)
(define substitute-in-t (substitute-template '(((1 2)
(3 4 1)
5))))
(define p '(Payload#0 Payload#1 Payload#2 Payload#3 Payload#4 Payload#5 Payload#6))
(check-equal? (substitute-in-t p)
'(((Payload#1 Payload#2)
(Payload#3 Payload#4 Payload#1)
Payload#5)))
(define out-of-bounds-generating-template-substitution (substitute-template '(7)))
(check-exn exn:fail:contract? (λ () (out-of-bounds-generating-template-substitution p)))
(parameterize ((current-not-found-handler (λ (idx max) (format "?~a" idx))))
(check-equal? (out-of-bounds-generating-template-substitution p) '("?7"))))
Raku
(formerly Perl 6)
Explicitly not using strings, using one data structure to fill in another. Since it isn't a string, the output format removes the newlines from the template; line feed (white space in general) isn't particularly significant in Raku data structures. It does preserve the nesting though. In the second example, payload "buckets" that don't exist result in an undefined value being inserted; by default: Any.
say join "\n ", '##PAYLOADS:', |my @payloads = 'Payload#' X~ ^7;
for [
(((1, 2),
(3, 4, 1),
5),),
(((1, 2),
(10, 4, 1),
5),)
] {
say "\n Template: ", $_.raku;
say "Data structure: { @payloads[|$_].raku }";
}
- Output:
##PAYLOADS: Payload#0 Payload#1 Payload#2 Payload#3 Payload#4 Payload#5 Payload#6 Template: $(((1, 2), (3, 4, 1), 5),) Data structure: ((("Payload#1", "Payload#2"), ("Payload#3", "Payload#4", "Payload#1"), "Payload#5"),) Template: $(((1, 2), (10, 4, 1), 5),) Data structure: ((("Payload#1", "Payload#2"), (Any, "Payload#4", "Payload#1"), "Payload#5"),)
Refal
$ENTRY Go {
, (((1 2) (3 4 1) 5)): e.Template
, "Payload#0" "Payload#1" "Payload#2" "Payload#3"
"Payload#4" "Payload#5" "Payload#6": e.Payload
= <Prout <Subst (e.Payload) e.Template>>;
};
Subst {
(e.P) = ;
(e.P) s.I e.X = <Item s.I e.P> <Subst (e.P) e.X>;
(e.P) (e.X) e.Y = (<Subst (e.P) e.X>) <Subst (e.P) e.Y>;
};
Item {
0 t.I e.X = t.I;
s.N t.I e.X = <Item <- s.N 1> e.X>;
};
- Output:
(((Payload#1 Payload#2 )(Payload#3 Payload#4 Payload#1 )Payload#5 ))
REXX
version 1
/* REXX */
tok.=''
Do i=0 To 6
tok.i="'Payload#"i"'"
End
t1='[[[1,2],[3,4,1],5]]'
t2='[[[1,6],[3,4,7,0],5]]'
Call transform t1
Call transform t2
Exit
transform:
Parse Arg t 1 tt
/* http://rosettacode.org/wiki/Nested_templated_data */
/*
[[['Payload#1', 'Payload#2'],
['Payload#3', 'Payload#4', 'Payload#1'],
'Payload#5']]
*/
lvl=0
n.=0
o=''
w=''
used.=0
Do While t<>''
Parse Var t c +1 1 c3 +3 1 c2 +2
u=' '
v=' '
Select
When c3='],[' Then Do
o=o' '
w=w' '
t=substr(t,3)
End
When c2='],' Then Do
o=o' '
w=w' '
t=substr(t,2)
lvl=lvl-1
End
When c='[' Then
lvl=lvl+1
When c=']' Then
lvl=lvl-1
When c=',' Then
Nop
Otherwise Do
u=lvl
v=c
End
End
t=substr(t,2)
o=o||u
w=w||v
End
Say 'Template' tt
Do i=1 By 1 While w<>''
If i=1 Then Do
w=substr(w,4)
p=pos(' ',w)
Call o '[[['cont(left(w,p-1))'],'
w=substr(w,p)
End
Else Do
If left(w,3)='' Then Do
w=substr(w,4)
p=pos(' ',w)
Call o ' ['cont(left(w,p-1))'],'
w=substr(w,p)
End
Else Do
w=substr(w,3)
p=pos(' ',w)
Call o ' 'cont(left(w,p-1))']]'
w=substr(w,p)
End
End
End
Do i=0 To 6
If used.i=0 Then Say 'Payload' i 'not used'
End
Call o ' '
Return
o: Say arg(1)
Return
cont: Procedure Expose tok. used.
Parse Arg list
res=''
Do while list>''
Parse Var list i list
res= res tok(i)','
End
res=strip(res)
res=strip(res,'T',',')
Return res
tok: Procedure Expose tok. used.
Parse Arg i
If tok.i<>'' Then Do
used.i=1
Return tok.i
End
Else
Return "'Payload#" i "not defined'"
- Output:
Template [[[1,2],[3,4,1],5]] [[['Payload#1', 'Payload#2'], ['Payload#3', 'Payload#4', 'Payload#1'], 'Payload#5']] Payload 0 not used Payload 6 not used Template [[[1,6],[3,4,7,0],5]] [[['Payload#1', 'Payload#6'], ['Payload#3', 'Payload#4', 'Payload# 7 not defined', 'Payload#0'], 'Payload#5']] Payload 2 not used
version 2
/* REXX */
tok.=''
Do i=0 To 6
tok.i="'Payload#"i"'"
End
t1='[[[1,2],[ 3,4,1],5]]'
t2='1[[[1,6]],[[3,4[7] 0],5]3]9 [8] 9'
Call transform t1
Call transform t2
Exit
transform:
Parse Arg t 1 tt
t=space(t,0)
lvl=0
t.=0
used.=0
undefined=''
Do While t<>''
Parse Var t c +1 t
Select
When c='[' Then
lvl=lvl+1
When c=']' Then
lvl=lvl-1
When c=',' Then
Nop
Otherwise Do
t=c||t
p1=pos(']',t)
p2=pos('[',t)
Select
When p2=0 Then p=p1
When p1=0 Then p=p2
Otherwise p=min(p1,p2)
End
If p=0 Then Do
Call mem lvl': >'t'<'
t=''
End
Else Do
Call mem lvl': >'left(t,p-1)'<'
t=substr(t,p)
End
End
End
End
Call show
Return
mem:
z=t.0+1
t.z=arg(1)
t.0=z
Return
show:
Say tt
Say 'lvl Element'
Do i=1 To t.0
Parse Var t.i lvl ':' '>' cont '<'
ol=right(lvl,3) copies(' ',lvl*3)cont(cont)
Say ol
End
Do i=0 To 6
If used.i=0 Then Say 'Payload' i 'not used'
End
Do While undefined>''
Parse Var undefined i undefined
Say 'Payload' i 'is not defined'
End
Call o ' '
Return
cont: Procedure Expose tok. used. undefined
Parse Arg list
list=translate(list,' ',',')
res=''
Do while list>''
Parse Var list i list
res= res tok(i)','
End
res=strip(res)
res=strip(res,'T',',')
Return res
tok: Procedure Expose tok. used. undefined
Parse Arg i
If tok.i<>'' Then Do
used.i=1
Return tok.i
End
Else Do
If wordpos(i,undefined)=0 Then
undefined=undefined i
Return "'Payload#"i "not defined'"
End
o: Say arg(1)
Return
- Output:
[[[1,2],[ 3,4,1],5]] lvl Element 3 'Payload#1', 'Payload#2' 3 'Payload#3', 'Payload#4', 'Payload#1' 2 'Payload#5' Payload 0 not used Payload 6 not used 1[[[1,6]],[[3,4[7] 0],5]3]9 [8] 9 lvl Element 0 'Payload#1' 3 'Payload#1', 'Payload#6' 3 'Payload#3', 'Payload#4' 4 'Payload#7 not defined' 3 'Payload#0' 2 'Payload#5' 1 'Payload#3' 0 'Payload#9 not defined' 1 'Payload#8 not defined' 0 'Payload#9 not defined' Payload 2 not used Payload 7 is not defined Payload 9 is not defined Payload 8 is not defined
SETL
program substitution;
template := [[[1,2],[3,4,1],5]];
payload := {
[0,"Payload#0"], [1,"Payload#1"], [2,"Payload#2"], [3,"Payload#3"],
[4,"Payload#4"], [5,"Payload#5"], [6,"Payload#6"]
};
print(subst(template, payload));
proc subst(template, payload);
if not is_tuple(template) then
return(payload(template));
end if;
result := [];
loop for item in template do
result with:= subst(item, payload);
end loop;
return result;
end proc;
end program;
- Output:
[[['Payload#1' 'Payload#2'] ['Payload#3' 'Payload#4' 'Payload#1'] 'Payload#5']]
VBA
VBA allows arrays of variant, so the elements of an array can be both scalars as arrays of different sizes.
Public Sub test()
Dim t(2) As Variant
t(0) = [{1,2}]
t(1) = [{3,4,1}]
t(2) = 5
p = [{"Payload#0","Payload#1","Payload#2","Payload#3","Payload#4","Payload#5","Payload#6"}]
Dim q(6) As Boolean
For i = LBound(t) To UBound(t)
If IsArray(t(i)) Then
For j = LBound(t(i)) To UBound(t(i))
q(t(i)(j)) = True
t(i)(j) = p(t(i)(j) + 1)
Next j
Else
q(t(i)) = True
t(i) = p(t(i) + 1)
End If
Next i
For i = LBound(t) To UBound(t)
If IsArray(t(i)) Then
Debug.Print Join(t(i), ", ")
Else
Debug.Print t(i)
End If
Next i
For i = LBound(q) To UBound(q)
If Not q(i) Then Debug.Print p(i + 1); " is not used"
Next i
End Sub
- Output:
Payload#1, Payload#2 Payload#3, Payload#4, Payload#1 Payload#5 Payload#0 is not used Payload#6 is not used
Wren
import "./set" for Set
import "./sort" for Sort
var withPayload // recursive function
withPayload = Fn.new { |template, payload, used|
return template.map { |item|
if (item is List) {
return withPayload.call(item, payload, used)
} else {
used.add(item)
return "'%(payload[item])'"
}
}.toList
}
var p = ["Payload#0", "Payload#1", "Payload#2", "Payload#3", "Payload#4", "Payload#5", "Payload#6"]
var t = [[[1, 2], [3, 4, 1], 5]]
var used = []
System.print(withPayload.call(t, p, used))
System.print()
var unused = Set.new(0..6).except(Set.new(used)).toList
Sort.insertion(unused)
System.print("The unused payloads have indices of %(unused).")
- Output:
[[['Payload#1', 'Payload#2'], ['Payload#3', 'Payload#4', 'Payload#1'], 'Payload#5']] The unused payloads have indices of [0, 6].
zkl
Formatting is lost as zkl is format free. A pretty printer could be written but the tasks asks for a data structure.
Void is used as a marker for an unknown payload.
var payloads=[1..6].pump(List,"Payload#".append);
fcn get(n){ try{ payloads[n - 1] }catch{ Void } }
fcn sub(list){ list.pump(List, fcn(n){ if(n.isType(List)) sub(n) else get(n) }) }
foreach p in (T(
T(T(T(1, 2),
T(3, 4, 1),
5),),
T(T(T(1, 2),
T(10,4, 1),
5),))){
println(" Template: %s\nData structure: %s".fmt(p,sub(p)));
}
- Output:
Template: L(L(L(1,2),L(3,4,1),5)) Data structure: L(L(L("Payload#1","Payload#2"),L("Payload#3","Payload#4","Payload#1"),"Payload#5")) Template: L(L(L(1,2),L(10,4,1),5)) Data structure: L(L(L("Payload#1","Payload#2"),L(Void,"Payload#4","Payload#1"),"Payload#5"))
- Programming Tasks
- Solutions by Programming Task
- AutoHotkey
- BASIC
- Applesoft BASIC
- BASIC256
- Chipmunk Basic
- FreeBASIC
- GW-BASIC
- MSX Basic
- QBasic
- QB64
- Run BASIC
- Yabasic
- Bracmat
- C++
- Crystal
- Factor
- Go
- Haskell
- J
- Jq
- Julia
- Mathematica
- Wolfram Language
- M2000 Interpreter
- Nim
- Perl
- Phix
- Python
- R
- Racket
- Raku
- Refal
- REXX
- SETL
- VBA
- Wren
- Wren-set
- Wren-sort
- Zkl