3

I'm using natbib and an "apacite" bibliography style, in a report document class. I can easily do multiple cites. For example:

\citep{hilary2019, james2013}

Gives me:

(Hilary et al., 2019; D. A. James, 2013)

My question: I have many multiple citations like the above throughout my document, and I would like to order them by date (oldest to newest). I am not talking about the actual biblography, I am pointing to the example at the above. So for example, the above becomes:

\citep{hilary2019,james2013}

Should give me:

(D. A. James, 2013; Hilary et al., 2019)

Is there a way to automatise this? Rather than me having to go through each command and order my citations.

Any help would be great. Thank you!

yo'
  • 51,322
  • 1
    Hi there, I'm Tom from the Overleaf Support Team. Note that I removed the [tag:overleaf] as this is not directly Overleaf-related. I also think that natbib doesn't support sorting cites by year; for that you'll probably have to switch to biblatex, but I'm not an expert on biblatex really. Either way, it would be helpful if you provided a minimal working example that showed your setup. – yo' Jun 16 '20 at 14:39

1 Answers1

5

natbib has a sort option that allows you to sort \citep/\citet calls in the order the entries appear in the bibliography.

\documentclass[british]{article}
\usepackage[T1]{fontenc}
\usepackage[utf8]{inputenc}
\usepackage{babel}
\usepackage{csquotes}

\usepackage[sort]{natbib} \bibliographystyle{plainnat}

\begin{filecontents}{\jobname.bib} @book{aardvark, author = {Anne Aardvark}, title = {Ardvarking}, year = {2020}, } @book{zebra, author = {Zoe Zebra}, title = {Zebraing}, year = {2010}, } \end{filecontents}

\begin{document} \citep{zebra,aardvark}

\citep{aardvark,zebra}

\bibliography{\jobname} \end{document}

[Aardvark, 2020, Zebra, 2010]//[Aardvark, 2020, Zebra, 2010]


If you want to sort citations differently than the bibliography, some additional work is needed. I have demonstrated this for apalike in In-text citation sorted according to publication year with apalike bibliography style.

First we need to modify the .bst file in a way to share the expected citation sort order with us. That can be done by adding

FUNCTION {sort.again}
{
  year field.or.null sortify
  "   "
  * 
  sort.label
  *
  'sort.key$ :=
}

ITERATE {sort.again}

SORT

EXECUTE {newline$}

FUNCTION {produce.sortlist} { "\sortentry{" cite$

"}"

write$ newline$ }

ITERATE {produce.sortlist}

to the end of a renamed copy of the .bst file.

For plainnat.bst the modified plainnat-sortcites.bst would look like https://gist.github.com/moewew/783c43bd536de4198d5f5166c886fb61. The exact details can vary from style to style.

Then we need document-level code that can extract the sorting information from the .bbl file and use it for sorting. The following code is only slightly modified code from natbib.sty.

\documentclass[british]{article}
\usepackage[T1]{fontenc}
\usepackage[utf8]{inputenc}
\usepackage{babel}
\usepackage{csquotes}

\usepackage[sort]{natbib} \bibliographystyle{plainnat-sortcites}

\usepackage{etoolbox}

\makeatletter \newcommand{\sortentry}[1]{% \if@filesw \immediate\write@auxout{\string\scNAT@aux@sortentry{#1}}% \fi} \newcommand{\scNAT@aux@sortentry}{% \listgadd{\scNAT@bibsortlist}} \newcommand*{\scNAT@bibsortlist}{}

\newcommand*{\scNAT@citekeys}{}

\newcommand*{\scNAT@writetocitelistsort}[1]{% \ifinlist{#1}{\scNAT@citekeys} {\ifdefvoid{\NAT@cite@list} {\def\NAT@cite@list{#1}} {\expandafter\def\expandafter\NAT@cite@list\expandafter{\NAT@cite@list,#1}}% \listgadd{\scNAT@foundkeys}{#1}} {}}

% Let's be paranoid: we might have dropped an item that % has not made it to the bibliography yet \newcommand*{\scNAT@writetocitelistforgotten}[1]{% \ifinlist{#1}{\scNAT@foundkeys} {} {\ifdefvoid{\NAT@cite@list} {\def\NAT@cite@list{#1}} {\expandafter\def\expandafter\NAT@cite@list\expandafter{\NAT@cite@list,#1}}}}

\newcommand*{\scNAT@sortcites}[1]{% \let\NAT@cite@list@empty \let\scNAT@citekeys@empty \let\scNAT@foundkeys@empty \forcsvlist{\listadd{\scNAT@citekeys}}{#1}% \forlistloop{\scNAT@writetocitelistsort}{\scNAT@bibsortlist}% \forlistloop{\scNAT@writetocitelistforgotten}{\scNAT@citekeys}% }

\def\NAT@citex% [#1][#2]#3{% \NAT@reset@parser \NAT@sort@cites{#3}% \scNAT@sortcites{#3}%<- this is new \NAT@reset@citea @cite{\let\NAT@nm@empty\let\NAT@year@empty @for@citeb:=\NAT@cite@list\do {@safe@activestrue \edef@citeb{\expandafter@firstofone@citeb@empty}% @safe@activesfalse @ifundefined{b@@citeb@extra@b@citeb}{@citea% {\reset@font\bfseries ?}\NAT@citeundefined \PackageWarning{natbib}% {Citation `@citeb' on page \thepage \space undefined}\def\NAT@date{}}% {\let\NAT@last@nm=\NAT@nm\let\NAT@last@yr=\NAT@year \NAT@parse{@citeb}% \ifNAT@longnames@ifundefined{bv@@citeb@extra@b@citeb}{% \let\NAT@name=\NAT@all@names \global@namedef{bv@@citeb@extra@b@citeb}{}}{}% \fi \ifNAT@full\let\NAT@nm\NAT@all@names\else \let\NAT@nm\NAT@name\fi \ifNAT@swa\ifcase\NAT@ctype \if\relax\NAT@date\relax @citea\NAT@hyper@{\NAT@nmfmt{\NAT@nm}\NAT@date}% \else \ifx\NAT@last@nm\NAT@nm\NAT@yrsep \ifx\NAT@last@yr\NAT@year \def\NAT@temp{{?}}% \ifx\NAT@temp\NAT@exlab\PackageWarningNoLine{natbib}% {Multiple citation on page \thepage: same authors and year\MessageBreak without distinguishing extra letter,\MessageBreak appears as question mark}\fi \NAT@hyper@{\NAT@exlab}% \else\unskip\NAT@spacechar \NAT@hyper@{\NAT@date}% \fi \else @citea\NAT@hyper@{% \NAT@nmfmt{\NAT@nm}% \hyper@natlinkbreak{% \NAT@aysep\NAT@spacechar}{@citeb@extra@b@citeb }% \NAT@date }% \fi \fi \or@citea\NAT@hyper@{\NAT@nmfmt{\NAT@nm}}% \or@citea\NAT@hyper@{\NAT@date}% \or@citea\NAT@hyper@{\NAT@alias}% \fi \NAT@def@citea \else \ifcase\NAT@ctype \if\relax\NAT@date\relax @citea\NAT@hyper@{\NAT@nmfmt{\NAT@nm}}% \else \ifx\NAT@last@nm\NAT@nm\NAT@yrsep \ifx\NAT@last@yr\NAT@year \def\NAT@temp{{?}}% \ifx\NAT@temp\NAT@exlab\PackageWarningNoLine{natbib}% {Multiple citation on page \thepage: same authors and year\MessageBreak without distinguishing extra letter,\MessageBreak appears as question mark}\fi \NAT@hyper@{\NAT@exlab}% \else \unskip\NAT@spacechar \NAT@hyper@{\NAT@date}% \fi \else @citea\NAT@hyper@{% \NAT@nmfmt{\NAT@nm}% \hyper@natlinkbreak{\NAT@spacechar\NAT@@open\if#1\else#1\NAT@spacechar\fi}% {@citeb@extra@b@citeb}% \NAT@date }% \fi \fi \or@citea\NAT@hyper@{\NAT@nmfmt{\NAT@nm}}% \or@citea\NAT@hyper@{\NAT@date}% \or@citea\NAT@hyper@{\NAT@alias}% \fi \if\relax\NAT@date\relax \NAT@def@citea \else \NAT@def@citea@close \fi \fi }}\ifNAT@swa\else\if#2\else\NAT@cmt#2\fi \if\relax\NAT@date\relax\else\NAT@@close\fi\fi}{#1}{#2}} \makeatother

\begin{filecontents}{\jobname.bib} @book{aardvark, author = {Anne Aardvark}, title = {Ardvarking}, year = {2020}, } @book{zebra, author = {Zoe Zebra}, title = {Zebraing}, year = {2010}, } \end{filecontents}

\begin{document} \citep{zebra,aardvark}

\citep{aardvark,zebra}

\bibliography{\jobname} \end{document}

(Zebra, 2010; Aardvark, 2020)//(Zebra, 2010; Aardvark, 2020)

moewe
  • 175,683
  • Hi @moewe, I am trying to replicate this but I don't understand what needs to be done after including that function in .bst file. When you say "Then we need document-level code that can extract the sorting information from the .bbl file and use it for sorting. The following code is only slightly modified code from natbib.sty." - do we have to change anything in the .sty file? It looks like the lines of code you have after this are from .tex file? Thanks – Daniela Apr 08 '23 at 09:19
  • 1
    @Daniela The code can go into the preamble of your .tex file as shown in the MWE (after natbib is loaded). (The MWE in the post can be compiled as-is without change if you have plainnat-sortcites.bst.) Do not change any .sty files that come for your TeX distribution (in particular do not edit natbib.sty). – moewe Apr 08 '23 at 09:56
  • Thanks @moewe, unfortunately it does not work for me since I am using \usepackage[natbibapa]{apacite}, and not natbib package. I asked this question (https://tex.stackexchange.com/questions/682091/multiple-citations-according-to-year-using-natbibapa-apacite) if anyone happens to know how to do this with apacite. Thanks! – Daniela Apr 08 '23 at 22:45