3

This is the converse of: Duplicate keys in citation

As before, using bibtex, Natbib w/ sort&compress option.

\def\grpA{key1,key2,key3}
\def\grpB{key2,key3,key4}

Group A\citep{grpA} discusses X, whilst set B\citep{grpB} discusses Y. 
The common discussion points\citep{key2,key3} are bla bla bla...

I would like to be able to determine the union of grpA and grpB, IE which keys are in BOTH groups (in this case key2 and key3), discarding all other keys.

How can a command be written which takes the inputs \grpA and \grpB, returning the UNION by key? For those of you who understand SQL, equivalent of an inner join.

2 Answers2

4

Sadly you didn't accept my answer in part I, as you just need to move an \else :-)

\documentclass{article}

\usepackage{natbib}

\begin{document}

\def\grpA{key1,key2,key3}
\def\grpB{key2,key3,key4,key5}
\def\merge#1{\mergexx#1,\relax,}
\def\mergexx{\expandafter\mergex}
\def\mergex#1,{%
\ifx\relax#1\else
\ifcsname @??#1\endcsname\else
#1,\expandafter\ifx\csname @??#1\endcsname\relax\fi
\fi
\expandafter\mergexx
\fi}

\def\ijoin#1{\ijoinxx#1,\relax,}
\def\ijoinxx{\expandafter\ijoinx}
\def\ijoinx#1,{%
\ifx\relax#1\else
\ifcsname @??#1\endcsname#1,\else
\expandafter\ifx\csname @??#1\endcsname\relax\fi
\fi
\expandafter\ijoinxx
\fi}

\let\oldcitep\citep
\protected\def\citep#1{{\xdef\tmp{\noexpand\oldcitep{\merge{#1}}}}\tmp}

\protected\def\citepj#1{{\xdef\tmp{\noexpand\oldcitep{\ijoin{#1}}}}\tmp}

The first set\citep{\grpA} and the second set\citep{\grpB} discuss XYZ. 
In total\citep{\grpA,\grpB}, the bla bla bla is in common.


Group A\citep{\grpA} discusses X, whilst set B\citep{\grpB} discusses Y. 
The common discussion points\citepj{\grpA,\grpB} are bla bla bla...

\end{document}

Produces

\citation{key1,key2,key3,}
\citation{key2,key3,key4,key5,}
\citation{key1,key2,key3,key4,key5,}
\citation{key1,key2,key3,}
\citation{key2,key3,key4,key5,}
\citation{key2,key3,}

with the last line showing the join/union of the two groups.

David Carlisle
  • 757,742
1

Building on the previous answer, I propose two macros:

  • \intersectgroups{<list of groups>}{<control sequence>} that builds a new group computing the intersection of the groups;

  • \citeij{<list of groups>} that cites the elements present in all groups.

\begin{filecontents*}{\jobname.bib}
@article{key1,
 author={A. Author},
 title={Title},
 journal={Journal},
 year={2000},
}
@article{key2,
 author={A. Buthor},
 title={Title},
 journal={Journal},
 year={2000},
}
@article{key3,
 author={A. Cuthor},
 title={Title},
 journal={Journal},
 year={2000},
}
@article{key4,
 author={A. Duthor},
 title={Title},
 journal={Journal},
 year={2000},
}
@article{key5,
 author={A. Euthor},
 title={Title},
 journal={Journal},
 year={2000},
}
\end{filecontents*}

\documentclass{article}
\usepackage[sort&compress]{natbib}

\usepackage{xparse}
\ExplSyntaxOn

%%% Old code start
\AtBeginDocument{
 \cs_set_eq:Nc \adp_orig_citex:wwn { @citex }
 \cs_set:cpn { @citex } [ #1 ] [ #2 ] #3 
  {
   \clist_set:Nx \l_tmpa_clist { #3 }
   \clist_remove_duplicates:N \l_tmpa_clist
   \adp_orig_citex:nnV { #1 } { #2 } \l_tmpa_clist
  }
} % end of \AtBeginDocument
\cs_new:Npn \adp_orig_citex:nnn #1 #2 #3
 {
  \adp_orig_citex:wwn [ #1 ] [ #2 ] { #3 }
 }
\cs_generate_variant:Nn \adp_orig_citex:nnn { nnV }

\seq_new:N \l_adp_intersection_seq
\NewDocumentCommand{\intersectgroups}{mm}
 {
  \adp_intersectgroups:nn { #1 } { #2 }
 }
%%% Old code end

%%% New code start
\NewDocumentCommand{\citeij}{m}
 {
  \adp_intersectgroups:nn { #1 } { \l_adp_temp_clist }
  \clist_if_empty:NTF \l_adp_temp_clist
   { ``Empty list!'' }
   { \citep{\l_adp_temp_clist } }
 }

\seq_new:N \l_adp_groups_seq
\clist_new:N \l_adp_intersection_clist
\clist_new:N \l_adp_temp_clist

\cs_new_protected:Npn \adp_intersectgroups:nn #1 #2
 {
  \seq_set_from_clist:Nn \l_adp_groups_seq { #1 }
  \seq_pop_left:NN \l_adp_groups_seq \l_adp_first_item_tl
  \clist_set:Nx \l_adp_intersection_clist { \l_adp_first_item_tl }
  \seq_map_inline:Nn \l_adp_groups_seq
   {
    \clist_clear:N \l_adp_temp_clist
    \clist_map_inline:Nn \l_adp_intersection_clist
     {
      \clist_if_in:NnT ##1 { ####1 }
       { \clist_put_right:Nn \l_adp_temp_clist { ####1 } }
     }
    \clist_set_eq:NN \l_adp_intersection_clist \l_adp_temp_clist
   }
  \clist_set_eq:NN #2 \l_adp_intersection_clist
 }
%%% New code end

\ExplSyntaxOff

\begin{document}

\def\grpA{key1,key2,key3}
\def\grpB{key3,key4,key5}

\intersectgroups{\grpA,\grpB}{\grpC}

\citeij{\grpA,\grpB}

\citeij{\grpC}


The first set \citep{\grpA} and the second set \citep{\grpB} discuss XYZ. 
In total \citep{\grpA,\grpB}, the bla bla bla is in common.

\bibliographystyle{plainnat}
\bibliography{\jobname}

\end{document}

Note that \intersectgroups and \citeij accept as many items as you want (at least one, of course).

egreg
  • 1,121,712