Nested templated data: Difference between revisions
Line 226:
Append res, (curpayload$,)
if exist(payloads, curpayload$) then
delete payloads, curpayload$
if not exist(used, curpayload$) then append used, curpayload$
end if
p++
|
Revision as of 23:21, 5 December 2018
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
:
<lang># 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'</lang>
The correct output should have the following structure, (although spacing and linefeeds may differ, the nesting and order should follow): <lang>[[['Payload#1', 'Payload#2'],
['Payload#3', 'Payload#4', 'Payload#1'], 'Payload#5']]</lang>
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.
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.
<lang factor>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@</lang>
- 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: <lang html>Template:Index .P n</lang> 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.
<lang go>package main
import (
"fmt" "os" "sort" "strings" "text/template"
)
func main() {
const t = `[[[[[:Template:Index .P 1]], Template:Index .P 2], [[[:Template:Index .P 3]], Template:Index .P 4, Template:Index .P 1], Template: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("Template:Index .P %d", k)) { unused = append(unused, k) } } sort.Ints(unused) fmt.Println("\nThe unused payloads have indices of :", unused)
}</lang>
- Output:
[[['Payload#1', 'Payload#2'], ['Payload#3', 'Payload#4', 'Payload#1'], 'Payload#5']] The unused payloads have indices of : [0 6]
Julia
The array structure needs to be specified as Any type of data, to allow later assignment of strings to the paces in the array where there are integers. <lang julia>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)
</lang>
- Output:
Array{Any,1}[[Any["Payload#1", "Payload#2"], Any["Payload#3", "Payload#4", "Payload#1"], "Payload#5"]]
M2000 Interpreter
<lang 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$ </lang>
- 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
Perl
Only handles nesting one level deep. Missing data is undef
in the data structure, an empty string in the pretty-printer.
<lang perl>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] ); </lang>
- Output:
[ [ "Payload#1", "Payload#2" ], [ "Payload#3", "Payload#4", "Payload#1" ], "Payload#5" ] [ [ "Payload#1", "Payload#2" ], [ "", "Payload#4", "Payload#1" ], "Payload#5" ]
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 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;
for [
(((1, 2), (3, 4, 1), 5),),
(((1, 2), (10, 4, 1), 5),) ] { say "\n Template: ", $_.perl; say "Data structure: { @payloads[|$_].perl }";
}</lang>
- 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"),)
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 <lang Phix>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</lang>
{{{"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. <lang python>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 '-')</lang>
- 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
REXX
version 1
<lang rexx>/* 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'"</lang>
- 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
<lang rexx>/* 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</lang>
- 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
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. <lang zkl>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) }) }</lang> <lang zkl>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)));
}</lang>
- 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"))