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!

1
  • 1
    Hi there, I'm Tom from the Overleaf Support Team. Note that I removed the 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, 2020 at 14:39

1 Answer 1

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)

3
  • 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 8, 2023 at 9: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 8, 2023 at 9: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 (tex.stackexchange.com/questions/682091/…) if anyone happens to know how to do this with apacite. Thanks!
    – Daniela
    Apr 8, 2023 at 22:45

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .