Answers.Body: <p>You can do this directly on UniProt: <a href="https://www.uniprot.org/uploadlists/" rel="nofollow noreferrer">https://www.uniprot.org/uploadlists/</a></p>
  <p>Just paste or upload your list of UniProt IDs, and select &quot;UniProtKB AC/ID&quot; in the &quot;From&quot; field and &quot;UniParc&quot; in the &quot;To&quot; field</p>
  <p><a href="https://i.sstatic.net/Wu1o0.png" rel="nofollow noreferrer"><img src="https://i.sstatic.net/Wu1o0.png" alt="screenshot of the relevant Uniprot.org page" /></a></p>
  <hr />
  <p>I've also written a script, pasted below, that can do this with some useful options:</p>
  <pre class="lang-none prettyprint-override"><code>$ uniprot_map.pl -h
  
  uniprot_map.pl will connect to UniProt and map IDs from the input file to ehatever ID was requested.
  
  USAGE:
         uniprot_map.pl [options] &lt;ID_LIST&gt;
  
  OPTIONS:
        -h : Print this help and exit.
        -f : From ID type. This is the type of ID found in the input file.
        -F : Format. See http://www.uniprot.org/faq/28#batch_retrieval_of_entries for details. 
  
        -l : When a requested ID maps to many output IDs, print only the first (probably the best) match.
        -L : List all recognised ID types.
        -u : Print unreviewed (trEMBL) prots as well. By default, if an ID maps to SWISSPROT and trEMBL IDs 
             only the SWISSPROTs will be printed, use this flag to print trEMBL as well.
        -t : To ID. This is the ID type that the input IDs will be mapped to.
        -v : Verbose. Print progress messages to STDERR.
  </code></pre>
  <p>If you save the script as <code>uniprot_map.pl</code> in a directory in your PATH and make it executable, then you can use a file like this:</p>
  <pre><code>$ cat file
  P31946
  P62258
  </code></pre>
  <p>And feed it to the script with the appropriate options to get the mapping:</p>
  <pre class="lang-perl prettyprint-override"><code>$ uniprot_map.pl -f ID -t UniParc file
  P31946  UPI000013C714
  P62258  UPI0000021A46
  2 of 2
  </code></pre>
  <p>The script:</p>
  <pre class="lang-perl prettyprint-override"><code>#!/usr/bin/perl
  use strict;
  use warnings;
  use LWP::UserAgent;
  use Getopt::Std;
  my %opts;
  getopts('Lsvuhf:F:t:l', \%opts);
  my <span class="math-container">$base = 'http://www.uniprot.org';
  my $</span>verbose=<span class="math-container">$opts{v}||undef;
  my $</span>tool = 'mapping';
  my (@NAMES,@names);
  my <span class="math-container">$print_only_first=$</span>opts{l}||undef;
  my <span class="math-container">$allow_trembl=$</span>opts{u}||undef;
  list_ids() if <span class="math-container">$opts{L};
  &amp;usage() if $</span>opts{h};
  
  &amp;usage() unless $ARGV[0];
  
  ####################################
  # Collect the IDs we want to match #
  ####################################
  foreach my <span class="math-container">$ar(@ARGV){
  if (-e $ar){
  open(A, $ar);
  while(&lt;A&gt;){
      chomp;
      push @names,$_;
  }
  }
  else{push @names,$</span>ar};
  }
  
  ######################################
  # What are we matching FROM and TO ? #
  ######################################
  my <span class="math-container">$from=$</span>opts{f}||'ID';
  my <span class="math-container">$to = $</span>opts{t}||'ACC';
  
  if(<span class="math-container">$opts{t}){
  $to=translate_terms($to);
  }
  if($</span>opts{f}){
      <span class="math-container">$from=translate_terms($</span>from);
  }
  #################
  # Output format #
  #################
  my <span class="math-container">$format = $</span>opts{F}||'tab';
  #my @query=
  
  
  my <span class="math-container">$agent = LWP::UserAgent-&gt;new;
  push @{$</span>agent-&gt;requests_redirectable}, 'POST';
  
  my <span class="math-container">$params= {
  'from' =&gt; $from,
  'to' =&gt; $to,
  'format' =&gt; $</span>format,
      'query' =&gt; &quot;@names&quot;
  };
  
  print STDERR &quot;Requesting...\t&quot; if <span class="math-container">$verbose;
  my $</span>try_again=1;
  my <span class="math-container">$response;
  while($</span>try_again==1){
      <span class="math-container">$response = get_response($</span>params);
      if(defined(<span class="math-container">$response-&gt;is_success)){$try_again=0}
  elsif($</span>verbose){print STDERR &quot;Failed, retrying...\n&quot;; }
  }
  
  if( <span class="math-container">$print_only_first) 
  {
  if($response-&gt;is_success){
  my %k;
  my @a=split(/\n/,$response-&gt;content);
  foreach my $line(@a){
      next if $line=~/From/;
      my @b=split(/\t/,$line);
      next if(defined($k{$b[0]}));
      $k{$b[0]}=$b[1];
  }
  map{print STDOUT "$_\t$k{$_}\n"}keys(%k);
  }
  else{
  die 'Failed, got ' . $response-&gt;status_line . ' for ' . $response-&gt;request-&gt;uri . "\n";
  }
  }
  else{
  if($response-&gt;is_success){ 
  my %map;
  my @a=split(/\n/,$response-&gt;content);
  #############################
      # remove "From   To"   line #
      #############################
  shift(@a) if $a[0] =~/^From/i;
  my %kk;
  map{
      ########################################################
          # UniProt sometimes returns the SAME line twice    #
          ########################################################
      $kk{$_}++;
      #print STDOUT "$_\n" unless $kk{$_}&gt;1; 
      next if $kk{$_}&gt;1; 
      my @b=split(/\t/);
      push @{$map{$b[0]}},$</span>b[1];
      }@a;
  
      foreach my <span class="math-container">$query (keys(%map)) {
      my %sw;
      foreach my $target (@{$map{$query}}) {
      #############################################
              # Does this prot have SWISSPROT IDs?        #
              #############################################
      if ($to eq 'ID')
      {
          my @b=split(/_/,$target);
          $sw{$target}++ if length($b[0])!=6;
      }
      }
      foreach my $target (@{$map{$query}}) {
      ################################################
      # If a protein has a least one SWISSPROT ID    #
      # skip printing its trEMBL ones unless -u      #
      ################################################
      if ($to eq 'ID' and not $allow_trembl and scalar(keys(%sw)) &gt; 0) {
          print "$query\t$target\n" if defined($sw{$target});
      }
      else {
          print "$query\t$</span>target\n&quot;;
          }
          }
      }
      
      ## Count how many were actually found
      my %found;
      foreach my <span class="math-container">$resp (@a){
      #print STDERR "R:$resp\t";
      foreach my $id (@names){
      #print STDERR "I:$id\n";
      $found{$id}++ if $resp=~/^$</span>id\t/;
          }
          
      }
      print STDERR scalar(keys(%found)) . &quot; of &quot; . scalar @names . &quot;\n&quot;;
  
      }
      else{
          die 'Failed, got ' . <span class="math-container">$response-&gt;status_line . 
      ' for ' . $</span>response-&gt;request-&gt;uri . &quot;\n&quot;;
      }
  }
  ################################################
  # This will translate <span class="math-container">$to and $</span>from values     #
  # between the names used in uniprot flat files #
  # and those used by the uniprot database       #
  ################################################
  sub translate_terms{
      my <span class="math-container">$id=shift();
  my %hash=(
  "AC" =&gt; "ACC", "ID" =&gt; "ID", "UniParc" =&gt; "UPARC", "UniRef50" =&gt; "NF50", "UniRef90" =&gt; "NF90", "UniRef100" =&gt; "NF100", "EMBL/GenBank/DDBJ" =&gt; "EMBL_ID", "EMBL/GenBank/DDBJ CDS" =&gt; "EMBLD", "PIR" =&gt; "PIR", "UniGene" =&gt; "UNIGENE_ID", "GI number*" =&gt; "P_GI", "IPI" =&gt; "P_IPI", "RefSeq" =&gt; "P_REFSEQ_AC", "PDB" =&gt; "PDB_ID", "DisProt" =&gt; "DISPROT_ID", "HSSP" =&gt; "HSSP_ID", "DIP" =&gt; "DIP_ID", "MINT" =&gt; "MINT_ID", "MEROPS" =&gt; "MEROPS_ID", "PeroxiBase" =&gt; "PEROXIBASE_ID", "PptaseDB" =&gt; "PPTASEDB_ID", "REBASE" =&gt; "REBASE_ID", "TCDB" =&gt; "TCDB_ID", "Aarhus/Ghent-2DPAGE" =&gt; "AARHUS_GHENT_2DPAGE_ID", "ECO2DBASE" =&gt; "ECO2DBASE_ID", "World-2DPAGE" =&gt; "WORLD_2DPAGE_ID", "Ensembl" =&gt; "ENSEMBL_ID", "Ensembl Protein" =&gt; "ENSEMBL_PRO_ID", "Ensembl  Trscrpt" =&gt; "ENSEMBL_TRS_ID", "Ensembl  Genomes" =&gt; "ENSEMBLGENOME_ID", "Ensembl    Genomes" =&gt; "Protein", "Ensembl Genomes" =&gt; "Transcript", "GeneID" =&gt; "P_ENTREZGENEID", "GenomeReviews" =&gt; "GENOMEREVIEWS_ID", "KEGG" =&gt; "KEGG_ID", "TIGR" =&gt; "TIGR_ID", "UCSC" =&gt; "UCSC_ID", "VectorBase" =&gt; "VECTORBASE_ID", "AGD" =&gt; "AGD_ID", "ArachnoServer" =&gt; "ARACHNOSERVER_ID", "CGD" =&gt; "CGD", "ConoServer" =&gt; "CONOSERVER_ID", "CYGD" =&gt; "CYGD_ID", "dictyBase" =&gt; "DICTYBASE_ID", "EchoBASE" =&gt; "ECHOBASE_ID", "EcoGene" =&gt; "ECOGENE_ID", "euHCVdb" =&gt; "EUHCVDB_ID", "EuPathDB" =&gt; "EUPATHDB_ID", "FlyBase" =&gt; "FLYBASE_ID", "GeneCards" =&gt; "GENECARDS_ID", "GeneDB_Spombe" =&gt; "GENEDB_SPOMBE_ID", "GeneFarm" =&gt; "GENEFARM_ID", "GenoList" =&gt; "GENOLIST_ID", "H-InvDB" =&gt; "H_INVDB_ID", "HGNC" =&gt; "HGNC_ID", "HPA" =&gt; "HPA_ID", "LegioList" =&gt; "LEGIOLIST_ID", "Leproma" =&gt; "LEPROMA_ID", "MaizeGDB" =&gt; "MAIZEGDB_ID", "MIM" =&gt; "MIM_ID", "MGI" =&gt; "MGI_ID", "NMPDR" =&gt; "NMPDR", "Orphanet" =&gt; "ORPHANET_ID", "PharmGKB" =&gt; "PHARMGKB_ID", "PseudoCAP" =&gt; "PSEUDOCAP_ID", "RGD" =&gt; "RGD_ID", "SGD" =&gt; "SGD_ID", "TAIR" =&gt; "TAIR_ID", "TubercuList" =&gt; "TUBERCULIST_ID", "WormBase" =&gt; "WORMBASE_ID", "WormBase Trscrpt" =&gt; "WORMBASE_TRS_ID", "WormBase Protein" =&gt; "WORMBASE_PRO_ID", "Xenbase" =&gt; "XENBASE_ID", "ZFIN" =&gt; "ZFIN_ID", "eggNOG" =&gt; "EGGNOG_ID", "HOGENOM" =&gt; "HOGENOM_ID", "HOVERGEN" =&gt; "HOVERGEN_ID", "OMA" =&gt; "OMA_ID", "OrthoDB" =&gt; "ORTHODB_ID", "ProtClustDB" =&gt; "PROTCLUSTDB_ID", "BioCyc" =&gt; "BIOCYC_ID", "Reactome" =&gt; "REACTOME_ID", "CleanEx" =&gt; "CLEANEX_ID", "GermOnline" =&gt; "GERMONLINE_ID", "DrugBank" =&gt; "DRUGBANK_ID", "NextBio" =&gt; "NEXTBIO_ID"
  );
  defined($</span>hash{<span class="math-container">$id}) ? 
  return($</span>hash{<span class="math-container">$id}) : 
  return($</span>id) ;
  }
  
  sub get_response{
      my <span class="math-container">$params=shift;
  my $</span>response = <span class="math-container">$agent-&gt;post("$</span>base/<span class="math-container">$tool/", $</span>params);
      while (my <span class="math-container">$wait = $</span>response-&gt;header('Retry-After')) {
      print STDERR &quot;Waiting (<span class="math-container">$wait)...\n";
  sleep $</span>wait;
      <span class="math-container">$response = $</span>agent-&gt;get(<span class="math-container">$response-&gt;base);
  }
  return($</span>response);
  
  }
  
  
  
  
  
  sub usage{
      <span class="math-container">$0=~s/.+?([^\/]+)$</span>/$1/;
  
  
      print STDERR &lt;&lt;EndOfHelp;
  
  $0 will connect to UniProt and map IDs from the input file to ehatever ID was requested.
  
  USAGE:
         $0 [options] &lt;ID_LIST&gt;
  
  OPTIONS:
        -h : Print this help and exit.
        -f : From ID type. This is the type of ID found in the input file.
        -F : Format. See http://www.uniprot.org/faq/28#batch_retrieval_of_entries for details. 
  
        -l : When a requested ID maps to many output IDs, print only the first (probably the best) match.
        -L : List all recognised ID types.
        -u : Print unreviewed (trEMBL) prots as well. By default, if an ID maps to SWISSPROT and trEMBL IDs 
             only the SWISSPROTs will be printed, use this flag to print trEMBL as well.
        -t : To ID. This is the ID type that the input IDs will be mapped to.
        -v : Verbose. Print progress messages to STDERR.
  EndOfHelp
  
      exit(0);
  
  }
  sub list_ids{
      open(HELP, &quot;| less&quot;) ;
      print HELP &lt;&lt;EndOfHelp;
  
  Database            Abbreviation
  ===================== UniProt =============================
  UniProtKB AC/ID :   ACC+ID
  UniProtKB AC    :   ACC
  UniProtKB ID    :   ID
  UniParc         :   UPARC
  UniRef50    :   NF50
  UniRef90    :   NF90
  UniRef100   :   NF100
  
  =============== Other sequence databases ==================
  EMBL/GenBank/DDBJ:  EMBL_ID
  EMBL/GenBank/DDBJ CDS:  EMBLD
  PIR     :   PIR
  UniGene     :   UNIGENE_ID
  GI number*  :   P_GI
  IPI     :   P_IPI
  RefSeq      :   P_REFSEQ_AC
  HGNC name       :       GENENAME
  ================== 3D structure databases =================
  PDB     :   PDB_ID
  DisProt     :   DISPROT_ID
  HSSP        :   HSSP_ID
  
  ============ Protein-protein interaction databases ========
  DIP     :   DIP_ID
  MINT        :   MINT_ID
  
  ============ Protein family/group databases ===============
  MEROPS      :   MEROPS_ID
  PeroxiBase  :   PEROXIBASE_ID
  PptaseDB    :   PPTASEDB_ID
  REBASE      :   REBASE_ID
  TCDB        :   TCDB_ID
  
  ================== 2D gel databases =======================
  Aarhus/Ghent-2DPAGE:  AARHUS_GHENT_2DPAGE_ID
  ECO2DBASE   :   ECO2DBASE_ID
  World-2DPAGE    :   WORLD_2DPAGE_ID
  
  ============= Genome annotation databases =================
  Ensembl         :   ENSEMBL_ID
  Ensembl Protein :   ENSEMBL_PRO_ID
  Ensembl Trscrpt :   ENSEMBL_TRS_ID
  Ensembl Genomes :   ENSEMBLGENOME_ID
  Ensembl Genomes :   Protein
  Ensembl Genomes :   Transcript
  GeneID          :   P_ENTREZGENEID
  GenomeReviews   :   GENOMEREVIEWS_ID
  KEGG        :   KEGG_ID 
  TIGR        :   TIGR_ID 
  UCSC        :   UCSC_ID 
  VectorBase  :   VECTORBASE_ID
  
  ============ Organism-specific gene databases =============
  AGD     :   AGD_ID  
  ArachnoServer   :   ARACHNOSERVER_ID
  CGD     :   CGD 
  ConoServer  :   CONOSERVER_ID
  CYGD        :   CYGD_ID 
  dictyBase   :   DICTYBASE_ID
  EchoBASE    :   ECHOBASE_ID
  EcoGene     :   ECOGENE_ID
  euHCVdb     :   EUHCVDB_ID
  EuPathDB    :   EUPATHDB_ID
  FlyBase     :   FLYBASE_ID
  GeneCards   :   GENECARDS_ID
  GeneDB_Spombe   :   GENEDB_SPOMBE_ID
  GeneFarm    :   GENEFARM_ID
  GenoList    :   GENOLIST_ID
  H-InvDB     :   H_INVDB_ID
  HGNC        :   HGNC_ID 
  HPA     :   HPA_ID  
  LegioList   :   LEGIOLIST_ID
  Leproma     :   LEPROMA_ID
  MaizeGDB    :   MAIZEGDB_ID
  MIM     :   MIM_ID  
  MGI     :   MGI_ID  
  NMPDR       :   NMPDR   
  Orphanet    :   ORPHANET_ID
  PharmGKB    :   PHARMGKB_ID
  PseudoCAP   :   PSEUDOCAP_ID
  RGD     :   RGD_ID  
  SGD     :   SGD_ID  
  TAIR        :   TAIR_ID 
  TubercuList :   TUBERCULIST_ID
  WormBase    :   WORMBASE_ID
  WormBase Trscrpt:   WORMBASE_TRS_ID
  WormBase Protein:   WORMBASE_PRO_ID
  Xenbase     :   XENBASE_ID
  ZFIN        :   ZFIN_ID
  
  ================= Phylogenomic databases ==================
  eggNOG      :   EGGNOG_ID
  HOGENOM     :   HOGENOM_ID
  HOVERGEN    :   HOVERGEN_ID
  OMA     :   OMA_ID
  OrthoDB     :   ORTHODB_ID
  ProtClustDB :   PROTCLUSTDB_ID
  
  =================== Enzyme and pathway ====================
  BioCyc      :   BIOCYC_ID
  Reactome    :   REACTOME_ID
  
  ================= Gene expression databases ===============
  CleanEx     :   CLEANEX_ID
  GermOnline  :   GERMONLINE_ID
  
  ========================== Other ==========================
  DrugBank    :   DRUGBANK_ID
  NextBio     :   NEXTBIO_ID
  
  EndOfHelp
  close(HELP);
      exit(0);
  }
  </code></pre>
  <p>If you have too many IDs to do in a single batch, you could either simply split the file into smaller ones and run the script on each file in a loop or modify the script to do it.</p>
  <p>Split the input:</p>
  <pre class="lang-sh prettyprint-override"><code>$ wc -l names
  $ wc -l names
  500000 names
  ## split into 500 files of 1K lines each
  $ split -l 1000 names chunk
  ## iterate over each chunk of names
  $ for i in chunk*; do uniprot_map.pl -f ID -t UniParc &quot;$i&quot; &gt;&gt; mapped; done
  </code></pre>
  
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2022-03-05T00:52:13.937Z
Answers.Text: Thank you @terdon for the detailed answer and your script! Let me try it out!
Answers.UserDisplayName: Johnny Tam
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2022-03-05T01:05:09.177Z
Answers.Text: Seems both of the solutions require ID list < 2Mb. I will try to look into the XML file of UniProt. Please check out: https://blog.liang2.tw/posts/2018/01/read-uniprotkb-xml/
Answers.UserDisplayName: Johnny Tam
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2022-03-05T09:36:16.430Z
Answers.Text: @JohnnyTam just split your file and run the script in a loop. Or change the script to run them in batches.
Answers.UserDisplayName: terdon
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2022-03-05T10:24:57.250Z
Answers.Text: @JohnnyTam see updated answer for how to split the input. Alternatively, if you can give me your list of names, I can have a go at modifying the script to handle them.
Answers.UserDisplayName: terdon
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2022-03-08T07:30:27.237Z
Answers.Text: Ops, I forgot I can split. It worked perfectly! Thank you very much!
Answers.UserDisplayName: Johnny Tam
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2022-03-04T12:13:03.623Z
Answers.LastActivityDate: 2022-03-05T10:24:27.867Z
Answers.LastEditDate: 2022-03-05T10:24:27.867Z
Answers.UserDisplayName: terdon
Body: <p>I want to map ~500,000 UniProt IDs to their representative UniRef90 IDs.</p>
  <p>What is the most efficient way of doing this?</p>
  <p>Do we have a table with the mapping?</p>
  
Tags: <uniprot>
Title: Efficient way of mapping UniProt IDs to representative UniRef90 IDs?
ThreadText: # Efficient way of mapping UniProt IDs to representative UniRef90 IDs?
  
  (Asked by: username_0 on 2022-03-04)
  
  I want to map ~500,000 UniProt IDs to their representative UniRef90 IDs.
  
  What is the most efficient way of doing this?
  
  Do we have a table with the mapping?
  
  **Tags:** uniprot
  
  
  ---
  
  ## 1 answers
  
  ### Answer by username_1 on 2022-03-04. Score: 2 | Accepted answer
  
  You can do this directly on UniProt: <https://www.uniprot.org/uploadlists/>
  
  Just paste or upload your list of UniProt IDs, and select "UniProtKB AC/ID" in the "From" field and "UniParc" in the "To" field
  
  [![screenshot of the relevant Uniprot.org page](https://i.sstatic.net/Wu1o0.png)](https://i.sstatic.net/Wu1o0.png)
  
  ---
  
  I've also written a script, pasted below, that can do this with some useful options:
  
  ```none
  $ uniprot_map.pl -h
  
  uniprot_map.pl will connect to UniProt and map IDs from the input file to ehatever ID was requested.
  
  USAGE:
         uniprot_map.pl [options] <ID_LIST>
  
  OPTIONS:
        -h : Print this help and exit.
        -f : From ID type. This is the type of ID found in the input file.
        -F : Format. See http://www.uniprot.org/faq/28#batch_retrieval_of_entries for details. 
  
        -l : When a requested ID maps to many output IDs, print only the first (probably the best) match.
        -L : List all recognised ID types.
        -u : Print unreviewed (trEMBL) prots as well. By default, if an ID maps to SWISSPROT and trEMBL IDs 
             only the SWISSPROTs will be printed, use this flag to print trEMBL as well.
        -t : To ID. This is the ID type that the input IDs will be mapped to.
        -v : Verbose. Print progress messages to STDERR.
  
  ```
  
  If you save the script as `uniprot_map.pl` in a directory in your PATH and make it executable, then you can use a file like this:
  
  ```
  $ cat file
  P31946
  P62258
  
  ```
  
  And feed it to the script with the appropriate options to get the mapping:
  
  ```perl
  $ uniprot_map.pl -f ID -t UniParc file
  P31946  UPI000013C714
  P62258  UPI0000021A46
  2 of 2
  
  ```
  
  The script:
  
  ```perl
  #!/usr/bin/perl
  use strict;
  use warnings;
  use LWP::UserAgent;
  use Getopt::Std;
  my %opts;
  getopts('Lsvuhf:F:t:l', \%opts);
  my $base = 'http://www.uniprot.org';
  my $verbose=$opts{v}||undef;
  my $tool = 'mapping';
  my (@NAMES,@names);
  my $print_only_first=$opts{l}||undef;
  my $allow_trembl=$opts{u}||undef;
  list_ids() if $opts{L};
  &usage() if $opts{h};
  
  &usage() unless $ARGV[0];
  
  ####################################
  # Collect the IDs we want to match #
  ####################################
  foreach my $ar(@ARGV){
  if (-e $ar){
  open(A, $ar);
  while(<A>){
      chomp;
      push @names,$_;
  }
  }
  else{push @names,$ar};
  }
  
  ######################################
  # What are we matching FROM and TO ? #
  ######################################
  my $from=$opts{f}||'ID';
  my $to = $opts{t}||'ACC';
  
  if($opts{t}){
  $to=translate_terms($to);
  }
  if($opts{f}){
      $from=translate_terms($from);
  }
  #################
  # Output format #
  #################
  my $format = $opts{F}||'tab';
  #my @query=
  
  my $agent = LWP::UserAgent->new;
  push @{$agent->requests_redirectable}, 'POST';
  
  my $params= {
  'from' => $from,
  'to' => $to,
  'format' => $format,
      'query' => "@names"
  };
  
  print STDERR "Requesting...\t" if $verbose;
  my $try_again=1;
  my $response;
  while($try_again==1){
      $response = get_response($params);
      if(defined($response->is_success)){$try_again=0}
  elsif($verbose){print STDERR "Failed, retrying...\n"; }
  }
  
  if( $print_only_first) 
  {
  if($response->is_success){
  my %k;
  my @a=split(/\n/,$response->content);
  foreach my $line(@a){
      next if $line=~/From/;
      my @b=split(/\t/,$line);
      next if(defined($k{$b[0]}));
      $k{$b[0]}=$b[1];
  }
  map{print STDOUT "$_\t$k{$_}\n"}keys(%k);
  }
  else{
  die 'Failed, got ' . $response->status_line . ' for ' . $response->request->uri . "\n";
  }
  }
  else{
  if($response->is_success){ 
  my %map;
  my @a=split(/\n/,$response->content);
  #############################
      # remove "From   To"   line #
      #############################
  shift(@a) if $a[0] =~/^From/i;
  my %kk;
  map{
      ########################################################
          # UniProt sometimes returns the SAME line twice    #
          ########################################################
      $kk{$_}++;
      #print STDOUT "$_\n" unless $kk{$_}>1; 
      next if $kk{$_}>1; 
      my @b=split(/\t/);
      push @{$map{$b[0]}},$b[1];
      }@a;
  
      foreach my $query (keys(%map)) {
      my %sw;
      foreach my $target (@{$map{$query}}) {
      #############################################
              # Does this prot have SWISSPROT IDs?        #
              #############################################
      if ($to eq 'ID')
      {
          my @b=split(/_/,$target);
          $sw{$target}++ if length($b[0])!=6;
      }
      }
      foreach my $target (@{$map{$query}}) {
      ################################################
      # If a protein has a least one SWISSPROT ID    #
      # skip printing its trEMBL ones unless -u      #
      ################################################
      if ($to eq 'ID' and not $allow_trembl and scalar(keys(%sw)) > 0) {
          print "$query\t$target\n" if defined($sw{$target});
      }
      else {
          print "$query\t$target\n";
          }
          }
      }
      
      ## Count how many were actually found
      my %found;
      foreach my $resp (@a){
      #print STDERR "R:$resp\t";
      foreach my $id (@names){
      #print STDERR "I:$id\n";
      $found{$id}++ if $resp=~/^$id\t/;
          }
          
      }
      print STDERR scalar(keys(%found)) . " of " . scalar @names . "\n";
  
      }
      else{
          die 'Failed, got ' . $response->status_line . 
      ' for ' . $response->request->uri . "\n";
      }
  }
  ################################################
  # This will translate $to and $from values     #
  # between the names used in uniprot flat files #
  # and those used by the uniprot database       #
  ################################################
  sub translate_terms{
      my $id=shift();
  my %hash=(
  "AC" => "ACC", "ID" => "ID", "UniParc" => "UPARC", "UniRef50" => "NF50", "UniRef90" => "NF90", "UniRef100" => "NF100", "EMBL/GenBank/DDBJ" => "EMBL_ID", "EMBL/GenBank/DDBJ CDS" => "EMBLD", "PIR" => "PIR", "UniGene" => "UNIGENE_ID", "GI number*" => "P_GI", "IPI" => "P_IPI", "RefSeq" => "P_REFSEQ_AC", "PDB" => "PDB_ID", "DisProt" => "DISPROT_ID", "HSSP" => "HSSP_ID", "DIP" => "DIP_ID", "MINT" => "MINT_ID", "MEROPS" => "MEROPS_ID", "PeroxiBase" => "PEROXIBASE_ID", "PptaseDB" => "PPTASEDB_ID", "REBASE" => "REBASE_ID", "TCDB" => "TCDB_ID", "Aarhus/Ghent-2DPAGE" => "AARHUS_GHENT_2DPAGE_ID", "ECO2DBASE" => "ECO2DBASE_ID", "World-2DPAGE" => "WORLD_2DPAGE_ID", "Ensembl" => "ENSEMBL_ID", "Ensembl Protein" => "ENSEMBL_PRO_ID", "Ensembl  Trscrpt" => "ENSEMBL_TRS_ID", "Ensembl  Genomes" => "ENSEMBLGENOME_ID", "Ensembl    Genomes" => "Protein", "Ensembl Genomes" => "Transcript", "GeneID" => "P_ENTREZGENEID", "GenomeReviews" => "GENOMEREVIEWS_ID", "KEGG" => "KEGG_ID", "TIGR" => "TIGR_ID", "UCSC" => "UCSC_ID", "VectorBase" => "VECTORBASE_ID", "AGD" => "AGD_ID", "ArachnoServer" => "ARACHNOSERVER_ID", "CGD" => "CGD", "ConoServer" => "CONOSERVER_ID", "CYGD" => "CYGD_ID", "dictyBase" => "DICTYBASE_ID", "EchoBASE" => "ECHOBASE_ID", "EcoGene" => "ECOGENE_ID", "euHCVdb" => "EUHCVDB_ID", "EuPathDB" => "EUPATHDB_ID", "FlyBase" => "FLYBASE_ID", "GeneCards" => "GENECARDS_ID", "GeneDB_Spombe" => "GENEDB_SPOMBE_ID", "GeneFarm" => "GENEFARM_ID", "GenoList" => "GENOLIST_ID", "H-InvDB" => "H_INVDB_ID", "HGNC" => "HGNC_ID", "HPA" => "HPA_ID", "LegioList" => "LEGIOLIST_ID", "Leproma" => "LEPROMA_ID", "MaizeGDB" => "MAIZEGDB_ID", "MIM" => "MIM_ID", "MGI" => "MGI_ID", "NMPDR" => "NMPDR", "Orphanet" => "ORPHANET_ID", "PharmGKB" => "PHARMGKB_ID", "PseudoCAP" => "PSEUDOCAP_ID", "RGD" => "RGD_ID", "SGD" => "SGD_ID", "TAIR" => "TAIR_ID", "TubercuList" => "TUBERCULIST_ID", "WormBase" => "WORMBASE_ID", "WormBase Trscrpt" => "WORMBASE_TRS_ID", "WormBase Protein" => "WORMBASE_PRO_ID", "Xenbase" => "XENBASE_ID", "ZFIN" => "ZFIN_ID", "eggNOG" => "EGGNOG_ID", "HOGENOM" => "HOGENOM_ID", "HOVERGEN" => "HOVERGEN_ID", "OMA" => "OMA_ID", "OrthoDB" => "ORTHODB_ID", "ProtClustDB" => "PROTCLUSTDB_ID", "BioCyc" => "BIOCYC_ID", "Reactome" => "REACTOME_ID", "CleanEx" => "CLEANEX_ID", "GermOnline" => "GERMONLINE_ID", "DrugBank" => "DRUGBANK_ID", "NextBio" => "NEXTBIO_ID"
  );
  defined($hash{$id}) ? 
  return($hash{$id}) : 
  return($id) ;
  }
  
  sub get_response{
      my $params=shift;
  my $response = $agent->post("$base/$tool/", $params);
      while (my $wait = $response->header('Retry-After')) {
      print STDERR "Waiting ($wait)...\n";
  sleep $wait;
      $response = $agent->get($response->base);
  }
  return($response);
  
  }
  
  sub usage{
      $0=~s/.+?([^\/]+)$/$1/;
  
      print STDERR <<EndOfHelp;
  
  $0 will connect to UniProt and map IDs from the input file to ehatever ID was requested.
  
  USAGE:
         $0 [options] <ID_LIST>
  
  OPTIONS:
        -h : Print this help and exit.
        -f : From ID type. This is the type of ID found in the input file.
        -F : Format. See http://www.uniprot.org/faq/28#batch_retrieval_of_entries for details. 
  
        -l : When a requested ID maps to many output IDs, print only the first (probably the best) match.
        -L : List all recognised ID types.
        -u : Print unreviewed (trEMBL) prots as well. By default, if an ID maps to SWISSPROT and trEMBL IDs 
             only the SWISSPROTs will be printed, use this flag to print trEMBL as well.
        -t : To ID. This is the ID type that the input IDs will be mapped to.
        -v : Verbose. Print progress messages to STDERR.
  EndOfHelp
  
      exit(0);
  
  }
  sub list_ids{
      open(HELP, "| less") ;
      print HELP <<EndOfHelp;
  
  Database            Abbreviation
  ===================== UniProt =============================
  UniProtKB AC/ID :   ACC+ID
  UniProtKB AC    :   ACC
  UniProtKB ID    :   ID
  UniParc         :   UPARC
  UniRef50    :   NF50
  UniRef90    :   NF90
  UniRef100   :   NF100
  
  =============== Other sequence databases ==================
  EMBL/GenBank/DDBJ:  EMBL_ID
  EMBL/GenBank/DDBJ CDS:  EMBLD
  PIR     :   PIR
  UniGene     :   UNIGENE_ID
  GI number*  :   P_GI
  IPI     :   P_IPI
  RefSeq      :   P_REFSEQ_AC
  HGNC name       :       GENENAME
  ================== 3D structure databases =================
  PDB     :   PDB_ID
  DisProt     :   DISPROT_ID
  HSSP        :   HSSP_ID
  
  ============ Protein-protein interaction databases ========
  DIP     :   DIP_ID
  MINT        :   MINT_ID
  
  ============ Protein family/group databases ===============
  MEROPS      :   MEROPS_ID
  PeroxiBase  :   PEROXIBASE_ID
  PptaseDB    :   PPTASEDB_ID
  REBASE      :   REBASE_ID
  TCDB        :   TCDB_ID
  
  ================== 2D gel databases =======================
  Aarhus/Ghent-2DPAGE:  AARHUS_GHENT_2DPAGE_ID
  ECO2DBASE   :   ECO2DBASE_ID
  World-2DPAGE    :   WORLD_2DPAGE_ID
  
  ============= Genome annotation databases =================
  Ensembl         :   ENSEMBL_ID
  Ensembl Protein :   ENSEMBL_PRO_ID
  Ensembl Trscrpt :   ENSEMBL_TRS_ID
  Ensembl Genomes :   ENSEMBLGENOME_ID
  Ensembl Genomes :   Protein
  Ensembl Genomes :   Transcript
  GeneID          :   P_ENTREZGENEID
  GenomeReviews   :   GENOMEREVIEWS_ID
  KEGG        :   KEGG_ID 
  TIGR        :   TIGR_ID 
  UCSC        :   UCSC_ID 
  VectorBase  :   VECTORBASE_ID
  
  ============ Organism-specific gene databases =============
  AGD     :   AGD_ID  
  ArachnoServer   :   ARACHNOSERVER_ID
  CGD     :   CGD 
  ConoServer  :   CONOSERVER_ID
  CYGD        :   CYGD_ID 
  dictyBase   :   DICTYBASE_ID
  EchoBASE    :   ECHOBASE_ID
  EcoGene     :   ECOGENE_ID
  euHCVdb     :   EUHCVDB_ID
  EuPathDB    :   EUPATHDB_ID
  FlyBase     :   FLYBASE_ID
  GeneCards   :   GENECARDS_ID
  GeneDB_Spombe   :   GENEDB_SPOMBE_ID
  GeneFarm    :   GENEFARM_ID
  GenoList    :   GENOLIST_ID
  H-InvDB     :   H_INVDB_ID
  HGNC        :   HGNC_ID 
  HPA     :   HPA_ID  
  LegioList   :   LEGIOLIST_ID
  Leproma     :   LEPROMA_ID
  MaizeGDB    :   MAIZEGDB_ID
  MIM     :   MIM_ID  
  MGI     :   MGI_ID  
  NMPDR       :   NMPDR   
  Orphanet    :   ORPHANET_ID
  PharmGKB    :   PHARMGKB_ID
  PseudoCAP   :   PSEUDOCAP_ID
  RGD     :   RGD_ID  
  SGD     :   SGD_ID  
  TAIR        :   TAIR_ID 
  TubercuList :   TUBERCULIST_ID
  WormBase    :   WORMBASE_ID
  WormBase Trscrpt:   WORMBASE_TRS_ID
  WormBase Protein:   WORMBASE_PRO_ID
  Xenbase     :   XENBASE_ID
  ZFIN        :   ZFIN_ID
  
  ================= Phylogenomic databases ==================
  eggNOG      :   EGGNOG_ID
  HOGENOM     :   HOGENOM_ID
  HOVERGEN    :   HOVERGEN_ID
  OMA     :   OMA_ID
  OrthoDB     :   ORTHODB_ID
  ProtClustDB :   PROTCLUSTDB_ID
  
  =================== Enzyme and pathway ====================
  BioCyc      :   BIOCYC_ID
  Reactome    :   REACTOME_ID
  
  ================= Gene expression databases ===============
  CleanEx     :   CLEANEX_ID
  GermOnline  :   GERMONLINE_ID
  
  ========================== Other ==========================
  DrugBank    :   DRUGBANK_ID
  NextBio     :   NEXTBIO_ID
  
  EndOfHelp
  close(HELP);
      exit(0);
  }
  
  ```
  
  If you have too many IDs to do in a single batch, you could either simply split the file into smaller ones and run the script on each file in a loop or modify the script to do it.
  
  Split the input:
  
  ```sh
  $ wc -l names
  $ wc -l names
  500000 names
  ## split into 500 files of 1K lines each
  $ split -l 1000 names chunk
  ## iterate over each chunk of names
  $ for i in chunk*; do uniprot_map.pl -f ID -t UniParc "$i" >> mapped; done
  
  ```
  
  > **Comments:**
  > **username_0**: Thank you @username_1 for the detailed answer and your script! Let me try it out!  
  > **username_0**: Seems both of the solutions require ID list < 2Mb. I will try to look into the XML file of UniProt. Please check out: https://blog.liang2.tw/posts/2018/01/read-uniprotkb-xml/  
  > **username_1**: @username_0 just split your file and run the script in a loop. Or change the script to run them in batches.  
  > **username_1**: @username_0 see updated answer for how to split the input. Alternatively, if you can give me your list of names, I can have a go at modifying the script to handle them.  
  > **username_0**: Ops, I forgot I can split. It worked perfectly! Thank you very much!  
  
  ---
  
  