TeX - LaTeX Asked by iago-lito on August 23, 2021
I am trying without success to combine these two approaches into something powerful that would allow me to zip-iterate over two lists and do arbitrary cool things:
zip{a,b,c}{1,2,3}{#1-#2 }
would expand to
a-1 b-2 c-3
And why not
zip[#1/#2][#3::#4]
{a/A,b/B,c/C}
{1::I,2::II,3::III}
{Grand #1 is #2 but grand #3 is #4.}
would expand to
Grand a is A but grand 1 is I.
Grand b is B but grand 2 is II.
Grand c is C but grand 3 is III.
My best attempt so far was to append this code after @BrunoLeFloch’s solution:
NewDocumentCommand{zip}{mmm}
{
cs_set:Npn __egreg_apply_aux:nn ##1 q_stop { #3 }
clist_map_zip_ii:VVN #1 #2 __egreg_apply_aux:nn
}
with no luck, and maybe the arcanes of Interface3 find me not pure-hearted enough to unveil their secrets yet :'(
Defining zip
in the first way is quite easy:
documentclass{article}
usepackage{xparse}
ExplSyntaxOn
NewDocumentCommand{zip}{mm +m}
{
seq_set_from_clist:Nn l__iagolito_zip_a_seq { #1 }
seq_set_from_clist:Nn l__iagolito_zip_b_seq { #2 }
cs_set:Nn __iagolito_zip:nn { #3 }
seq_mapthread_function:NNN l__iagolito_zip_a_seq l__iagolito_zip_b_seq __iagolito_zip:nn
}
seq_new:N l__iagolito_zip_a_seq
seq_new:N l__iagolito_zip_b_seq
ExplSyntaxOff
begin{document}
zip{a,b,c}{1,2,3}{#1-#2 }
end{document}
You can check this prints
a-1 b-2 c-3
If the two lists have different number of elements, the loop ends when either list ends.
The more complex features can be accomplished as well. Beware that the two optional argument must both appear, if the complex processing is needed.
The idea is to populate another sequence where the two lists are merged and then an auxiliary macro can be applied.
documentclass{article}
usepackage{xparse}
ExplSyntaxOn
NewDocumentCommand{zip}{oomm +m}
{
IfNoValueTF { #1 }
{ iagolito_zip_simple:nnn { #3 } { #4 } { #5 } }
{ iagolito_zip_full:nnnnn { #1 } { #2 } { #3 } { #4 } { #5 } }
}
seq_new:N l__iagolito_zip_a_seq
seq_new:N l__iagolito_zip_b_seq
seq_new:N l__iagolito_zip_c_seq
cs_new_protected:Nn iagolito_zip_simple:nnn
{
seq_set_from_clist:Nn l__iagolito_zip_a_seq { #1 }
seq_set_from_clist:Nn l__iagolito_zip_b_seq { #2 }
cs_set:Nn __iagolito_zip:nn { #3 }
seq_mapthread_function:NNN l__iagolito_zip_a_seq l__iagolito_zip_b_seq __iagolito_zip:nn
}
cs_new_protected:Nn iagolito_zip_full:nnnnn
{
seq_set_from_clist:Nn l__iagolito_zip_a_seq { #3 }
seq_set_from_clist:Nn l__iagolito_zip_b_seq { #4 }
seq_clear:N l__iagolito_zip_c_seq
cs_set:Npn __iagolito_zip_process:w #1 q_stop #2 q_stop { #5 }
seq_mapthread_function:NNN l__iagolito_zip_a_seq l__iagolito_zip_b_seq __iagolito_merge:nn
seq_map_inline:Nn l__iagolito_zip_c_seq { ##1 }
}
cs_new_protected:Nn __iagolito_merge:nn
{
seq_put_right:Nn l__iagolito_zip_c_seq { __iagolito_zip_process:w #1 q_stop #2 q_stop }
}
ExplSyntaxOff
begin{document}
zip{a,b,c}{1,2,3}{#1-#2 }
zip[#1/#2][#3::#4]
{a/A,b/B,c/C}
{1::I,2::II,3::III}
{Grand #1 is #2 but grand #3 is #4.par}
end{document}
If you want to pass macros expanding to lists, do one step expansion.
documentclass{article}
usepackage{xparse}
ExplSyntaxOn
NewDocumentCommand{zip}{oomm +m}
{
IfNoValueTF { #1 }
{ iagolito_zip_simple:oon { #3 } { #4 } { #5 } }
{ iagolito_zip_full:nnoon { #1 } { #2 } { #3 } { #4 } { #5 } }
}
seq_new:N l__iagolito_zip_a_seq
seq_new:N l__iagolito_zip_b_seq
seq_new:N l__iagolito_zip_c_seq
cs_new_protected:Nn iagolito_zip_simple:nnn
{
seq_set_from_clist:Nn l__iagolito_zip_a_seq { #1 }
seq_set_from_clist:Nn l__iagolito_zip_b_seq { #2 }
cs_set:Nn __iagolito_zip:nn { #3 }
seq_mapthread_function:NNN l__iagolito_zip_a_seq l__iagolito_zip_b_seq __iagolito_zip:nn
}
cs_generate_variant:Nn iagolito_zip_simple:nnn { oo }
cs_new_protected:Nn iagolito_zip_full:nnnnn
{
seq_set_from_clist:Nn l__iagolito_zip_a_seq { #3 }
seq_set_from_clist:Nn l__iagolito_zip_b_seq { #4 }
seq_clear:N l__iagolito_zip_c_seq
cs_set:Npn __iagolito_zip_process:w #1 q_stop #2 q_stop { #5 }
seq_mapthread_function:NNN l__iagolito_zip_a_seq l__iagolito_zip_b_seq __iagolito_merge:nn
seq_map_inline:Nn l__iagolito_zip_c_seq { ##1 }
}
cs_generate_variant:Nn iagolito_zip_full:nnnnn { nnoo }
cs_new_protected:Nn __iagolito_merge:nn
{
seq_put_right:Nn l__iagolito_zip_c_seq { __iagolito_zip_process:w #1 q_stop #2 q_stop }
}
ExplSyntaxOff
newcommand{listA}{a,b,c}
newcommand{listB}{1,2,3}
newcommand{listC}{a/A,b/B,c/C}
newcommand{listD}{1::I,2::II,3::III}
begin{document}
zip{a,b,c}{1,2,3}{#1-#2 }
zip{listA}{1,2,3}{#1-#2 }
zip{a,b,c}{listB}{#1-#2 }
zip{listA}{listB}{#1-#2 }
zip[#1/#2][#3::#4]
{a/A,b/B,c/C}
{1::I,2::II,3::III}
{Grand #1 is #2 but grand #3 is #4.par}
zip[#1/#2][#3::#4]
{listC}
{1::I,2::II,3::III}
{Grand #1 is #2 but grand #3 is #4.par}
zip[#1/#2][#3::#4]
{a/A,b/B,c/C}
{listD}
{Grand #1 is #2 but grand #3 is #4.par}
zip[#1/#2][#3::#4]
{listC}
{listD}
{Grand #1 is #2 but grand #3 is #4.par}
end{document}
The output is the same as before, just repeated four times for each instance.
Correct answer by egreg on August 23, 2021
EDIT to provide full answer to all scenarios posed by OP. As long as there are always two lists to combine, the effort can be done with listofitems
.
Optional sub-argument separators can be multi-token; however they cannot include /
or |
, though if this is an issue, let me know. Perhaps some accommodation can be had.
documentclass{article}
usepackage[T1]{fontenc}
usepackage{listofitems}
defzipaux{}
newcommandzip[1][]{%
deftmpA{#1}%
zipB%
}
newcommandzipB[1][]{%
expandafterzipCexpandafter{tmpA}{#1}%
}
newcommandzipC[5]{%
ifxrelax#1relax
setsepchar{,}%
readlist*argA{#3}%
ifxrelax#2relax
renewcommandzipaux[2]{#5}%
setsepchar{,}
else
renewcommandzipaux[3]{#5}%
setsepchar{,/#2}
fi
else
setsepchar{,/#1}%
readlist*argA{#3}%
ifxrelax#2relax
renewcommandzipaux[3]{#5}%
setsepchar{,}
else
renewcommandzipaux[4]{#5}%
setsepchar{,/#2}
fi
fi%
readlist*argB{#4}%
foreachitemzinargB{%
ifxrelax#1relax
ifxrelax#2relax
zipaux{argA[zcnt]}{argB[zcnt]}%
else
zipaux{argA[zcnt]}{argB[zcnt,1]}{argB[zcnt,2]}%
fi
else
ifxrelax#2relax
zipaux{argA[zcnt,1]}{argA[zcnt,2]}{argB[zcnt]}%
else
zipaux{argA[zcnt,1]}{argA[zcnt,2]}
{argB[zcnt,1]}{argB[zcnt,2]}%
fi
fi
}%
}
begin{document}
zip{a,b,c}{1,2,3}{#1-#2 }
zip[?]{a?A,b?B,c?C}{1,2,3}{(#1*#2)-#3 }
zip[?][::]{a?A,b?B,c?C}{1::X,2::Y,3::Z}{(#1*#2)-#3/#4 }
zip[][::]{a,b,c}{1::X,2::Y,3::Z}{(#1-#2)/#3 }
end{document}
Answered by Steven B. Segletes on August 23, 2021
The simple case with two arguments
documentclass{article}
begin{document}
defzip#1#2#3{%
defz##1##2{#3}%
xzip#1,relax#2,relax}
defxzip#1,#2relax#3,#4relax{%
z{#1}{#3}%
ifrelaxdetokenize{#2}relax
expandafterzzgobble
fi
xzip#2relax#4relax
}
defzzgobble#1relax#2relax{}
zip{a,b,c}{1,2,3}{#1-#2 }
end{document}
Answered by David Carlisle on August 23, 2021
Get help from others!
Recent Questions
Recent Answers
© 2024 TransWikia.com. All rights reserved. Sites we Love: PCI Database, UKBizDB, Menu Kuliner, Sharing RPP