web-dev-qa-db-fra.com

Trouvez la plus longue sous-chaîne de départ commune dans un ensemble de chaînes

C'est un défi de trouver le JavaScript le plus élégant, Ruby ou une autre solution à un problème relativement trivial.

Ce problème est un cas plus spécifique du problème de sous-chaîne commun le plus long . J'ai seulement besoin de trouver la plus longue sous-chaîne commune de départ dans un tableau. Cela simplifie considérablement le problème.

Par exemple, la sous-chaîne la plus longue dans [interspecies, interstelar, interstate] est "inters". Cependant, je n'ai pas besoin de trouver "ific" dans [specifics, terrific].

J'ai résolu le problème en codant rapidement une solution en JavaScript dans le cadre de mon réponse sur la complétion de tabulation de type Shell ( page de test ici ). Voici cette solution, légèrement modifiée:

function common_substring(data) {
  var i, ch, memo, idx = 0
  do {
    memo = null
    for (i=0; i < data.length; i++) {
      ch = data[i].charAt(idx)
      if (!ch) break
      if (!memo) memo = ch
      else if (ch != memo) break
    }
  } while (i == data.length && idx < data.length && ++idx)

  return (data[0] || '').slice(0, idx)
}

Ce le code est disponible dans ce Gist avec une solution similaire dans Ruby. Vous pouvez cloner le Gist comme un dépôt git pour l'essayer:

$ git clone git://Gist.github.com/257891.git substring-challenge

Je ne suis pas très satisfait de ces solutions. J'ai le sentiment qu'ils pourraient être résolus avec plus d'élégance et moins de complexité d'exécution - c'est pourquoi je poste ce défi.

Je vais accepter comme réponse la solution que je trouve la plus élégante ou concise. Voici, par exemple, un fou Ruby hack que je propose — définissant le & opérateur sur String:

# works with Ruby 1.8.7 and above
class String
  def &(other)
    difference = other.to_str.each_char.with_index.find { |ch, idx|
      self[idx].nil? or ch != self[idx].chr
    }
    difference ? self[0, difference.last] : self
  end
end

class Array
  def common_substring
    self.inject(nil) { |memo, str| memo.nil? ? str : memo & str }.to_s
  end
end

Les solutions en JavaScript ou Ruby sont préférées, mais vous pouvez montrer une solution intelligente dans d'autres langues tant que vous expliquez ce qui se passe. Seul le code de la bibliothèque standard s'il vous plaît.

Mise à jour: mes solutions préférées

J'ai choisi la solution de tri JavaScript par kennebec comme "réponse" car elle m'a paru à la fois inattendue et géniale. Si nous ne tenons pas compte de la complexité du tri réel (imaginons qu'il soit optimisé à l'infini par l'implémentation du langage), la complexité de la solution consiste simplement à comparer deux chaînes.

Autres excellentes solutions:

Merci d'avoir participé! Comme vous pouvez le voir dans les commentaires, j'ai beaucoup appris (même sur Ruby).

39
mislav

C'est une question de goût, mais il s'agit d'une simple version javascript: il trie le tableau, puis ne regarde que les premier et dernier éléments.

// plus longue sous-chaîne de départ commune dans un tableau

function sharedStart(array){
    var A= array.concat().sort(), 
    a1= A[0], a2= A[A.length-1], L= a1.length, i= 0;
    while(i<L && a1.charAt(i)=== a2.charAt(i)) i++;
    return a1.substring(0, i);
}

DÉMOS

sharedStart(['interspecies', 'interstelar', 'interstate'])  //=> 'inters'
sharedStart(['throne', 'throne'])                           //=> 'throne'
sharedStart(['throne', 'dungeon'])                          //=> ''
sharedStart(['cheese'])                                     //=> 'cheese'
sharedStart([])                                             //=> ''
sharedStart(['prefix', 'suffix'])                           //=> ''
55
kennebec

En Python:

>>> from os.path import commonprefix
>>> commonprefix('interspecies interstelar interstate'.split())
'inters'
38
Roberto Bonvallet

Ruby one-liner:

l=strings.inject{|l,s| l=l.chop while l!=s[0...l.length];l}
9
AShelly

Il vous suffit de parcourir toutes les chaînes jusqu'à ce qu'elles diffèrent, puis de prendre la sous-chaîne jusqu'à ce point.

Pseudocode:

loop for i upfrom 0
     while all strings[i] are equal
     finally return substring[0..i]

LISP commun:

(defun longest-common-starting-substring (&rest strings)
  (loop for i from 0 below (apply #'min (mapcar #'length strings))
     while (apply #'char=
                  (mapcar (lambda (string) (aref string i))
                          strings))
     finally (return (subseq (first strings) 0 i))))
9
Svante

Mon doublure Haskell:

import Data.List

commonPre :: [String] -> String
commonPre = map head . takeWhile (\(x:xs)-> all (==x) xs) . transpose

EDIT: barkmadley a donné une bonne explication du code ci-dessous. J'ajouterais également que haskell utilise l'évaluation paresseuse, afin que nous puissions être paresseux quant à notre utilisation de transpose; il ne transposera nos listes que dans la mesure nécessaire pour retrouver la fin du préfixe commun.

9
jberryman

Encore une autre façon de le faire: utilisez la cupidité regex.

words = %w(interspecies interstelar interstate)
j = '='
str = ['', *words].join(j)
re = "[^#{j}]*"

str =~ /\A
    (?: #{j} ( #{re} ) #{re} )
    (?: #{j}    \1     #{re} )*
\z/x

p $1

Et le one-liner, gracieuseté de mislav (50 caractères):

p ARGV.join(' ').match(/^(\w*)\w*(?: \1\w*)*$/)[1]
6
FMc

En Python je n'utiliserais rien d'autre que la fonction commonprefix existante que j'ai montrée dans une autre réponse, mais je n'ai pas pu m'empêcher de réinventer la roue :P. Voici mon approche basée sur les itérateurs:

>>> a = 'interspecies interstelar interstate'.split()
>>>
>>> from itertools import takewhile, chain, izip as Zip, imap as map
>>> ''.join(chain(*takewhile(lambda s: len(s) == 1, map(set, Zip(*a)))))
'inters'

Edit: Explication de la façon dont cela fonctionne.

Zip génère des tuples d'éléments en prenant un de chaque élément de a à la fois:

In [6]: list(Zip(*a))  # here I use list() to expand the iterator
Out[6]:
[('i', 'i', 'i'),
 ('n', 'n', 'n'),
 ('t', 't', 't'),
 ('e', 'e', 'e'),
 ('r', 'r', 'r'),
 ('s', 's', 's'),
 ('p', 't', 't'),
 ('e', 'e', 'a'),
 ('c', 'l', 't'),
 ('i', 'a', 'e')]

En mappant set sur ces éléments, j'obtiens une série de lettres uniques:

In [7]: list(map(set, _))  # _ means the result of the last statement above
Out[7]:
[set(['i']),
 set(['n']),
 set(['t']),
 set(['e']),
 set(['r']),
 set(['s']),
 set(['p', 't']),
 set(['a', 'e']),
 set(['c', 'l', 't']),
 set(['a', 'e', 'i'])]

takewhile(predicate, items) en prend des éléments alors que le prédicat est True; dans ce cas particulier, lorsque les sets ont un élément, c'est-à-dire que tous les mots ont la même lettre à cette position:

In [8]: list(takewhile(lambda s: len(s) == 1, _))
Out[8]:
[set(['i']),
 set(['n']), 
 set(['t']), 
 set(['e']), 
 set(['r']), 
 set(['s'])]

À ce stade, nous avons un ensemble d'itérations, contenant chacun une lettre du préfixe que nous recherchions. Pour construire la chaîne, nous chain les en un seul itérable, à partir duquel nous obtenons les lettres de join dans la chaîne finale.

La magie de l'utilisation des itérateurs est que tous les éléments sont générés à la demande, donc lorsque takewhile cesse de demander des éléments, le zipping s'arrête à ce point et aucun travail inutile n'est effectué. Chaque appel de fonction dans mon one-liner a un for implicite et un break implicite.

4
Roberto Bonvallet

Ce n'est probablement pas la solution la plus concise (cela dépend si vous avez déjà une bibliothèque pour cela), mais une méthode élégante consiste à utiliser un trie. J'utilise des essais pour implémenter la complétion d'onglets dans mon interpréteur de schéma:

http://github.com/jcoglan/heist/blob/master/lib/trie.rb

Par exemple:

tree = Trie.new
%w[interspecies interstelar interstate].each { |s| tree[s] = true }
tree.longest_prefix('')
#=> "inters"

Je les utilise également pour faire correspondre les noms de canaux avec des caractères génériques pour le protocole de Bayeux; voir ces:

http://github.com/jcoglan/faye/blob/master/client/channel.js

http://github.com/jcoglan/faye/blob/master/lib/faye/channel.rb

3
jcoglan

Juste pour le plaisir, voici une version écrite en (SWI-) PROLOG:

common_pre([[C|Cs]|Ss], [C|Res]) :-
  maplist(head_tail(C), [[C|Cs]|Ss], RemSs), !,
  common_pre(RemSs, Res).
common_pre(_, []).

head_tail(H, [H|T], T).

Fonctionnement:

?- S=["interspecies", "interstelar", "interstate"], common_pre(S, CP), string_to_list(CPString, CP).

Donne:

CP = [105, 110, 116, 101, 114, 115],
CPString = "inters".

Explication:

(SWI-) PROLOG traite les chaînes comme des listes de codes de caractères (nombres). Tous les prédicats common_pre/2 does est une correspondance de modèle récursive pour sélectionner le premier code (C) dans la tête de la première liste (chaîne, [C|Cs]) dans la liste de toutes les listes (toutes les chaînes, [[C|Cs]|Ss]), et ajoute le code correspondant C au résultat iff il est commun à toutes les têtes (restantes) de toutes les listes (chaînes), sinon il se termine.

Agréable, propre, simple et efficace ... :)

3
sharky

Une version javascript basée sur algorithme de @ Svante :

function commonSubstring(words){
    var iChar, iWord,
        refWord = words[0],
        lRefWord = refWord.length,
        lWords = words.length;
    for (iChar = 0; iChar < lRefWord; iChar += 1) {
        for (iWord = 1; iWord < lWords; iWord += 1) {
            if (refWord[iChar] !== words[iWord][iChar]) {
                return refWord.substring(0, iChar);
            }
        }
    }
    return refWord;
}
3
Mariano Desanze

La combinaison des réponses par kennebec, Florian F et jberryman donne le one-liner Haskell suivant:

commonPrefix l = map fst . takeWhile (uncurry (==)) $ Zip (minimum l) (maximum l)

Avec Control.Arrow on peut obtenir un formulaire sans point:

commonPrefix = map fst . takeWhile (uncurry (==)) . uncurry Zip . (minimum &&& maximum)
3
Bolo

Celui-ci est très similaire à la solution de Roberto Bonvallet, sauf dans Ruby.

chars = %w[interspecies interstelar interstate].map {|w| w.split('') }
chars[0].Zip(*chars[1..-1]).map { |c| c.uniq }.take_while { |c| c.size == 1 }.join

La première ligne remplace chaque mot par un tableau de caractères. Ensuite, j'utilise Zip pour créer cette structure de données:

[["i", "i", "i"], ["n", "n", "n"], ["t", "t", "t"], ...

map et uniq réduisez cela à [["i"],["n"],["t"], ...

take_while extrait les caractères du tableau jusqu'à ce qu'il en trouve un dont la taille n'est pas un (ce qui signifie que tous les caractères n'étaient pas les mêmes). Enfin, je join les rassemble.

2
Ben Marini

solution acceptée est cassé (par exemple, il renvoie a pour des chaînes comme ['a', 'ba']). Le correctif est très simple, vous devez littéralement changer seulement 3 caractères (de indexOf(tem1) == -1 à indexOf(tem1) != 0) et la fonction fonctionnerait comme prévu.

Malheureusement, lorsque j'ai essayé de modifier la réponse pour corriger la faute de frappe, SO m'a dit que "les modifications doivent comporter au moins 6 caractères". Je pouvais changez plus que ces 3 caractères, en améliorant le nommage et la lisibilité, mais cela semble un peu trop.

Voici donc une version fixe et améliorée (du moins de mon point de vue) de la solution de kennebec:

function commonPrefix(words) {
  max_Word = words.reduce(function(a, b) { return a > b ? a : b });
  prefix   = words.reduce(function(a, b) { return a > b ? b : a }); // min Word

  while(max_Word.indexOf(prefix) != 0) {
    prefix = prefix.slice(0, -1);
  }

  return prefix;
}

(le jsFiddle )

Notez qu'il utilise la méthode réduire (JavaScript 1.8) afin de trouver le max/min alphanumérique au lieu de trier le tableau puis de récupérer le premier et le dernier élément de celui-ci.

2
Alexis

Cela ne semble pas si compliqué si vous n'êtes pas trop préoccupé par les performances ultimes:

def common_substring(data)
  data.inject { |m, s| s[0,(0..m.length).find { |i| m[i] != s[i] }.to_i] }
end

L'une des caractéristiques utiles de l'injection est la capacité de pré-amorçage avec le premier élément du réseau interagi. Cela évite le contrôle de mémo nul.

puts common_substring(%w[ interspecies interstelar interstate ]).inspect
# => "inters"
puts common_substring(%w[ feet feel feeble ]).inspect
# => "fee"
puts common_substring(%w[ fine firkin fail ]).inspect
# => "f"
puts common_substring(%w[ alpha bravo charlie ]).inspect
# => ""
puts common_substring(%w[ fork ]).inspect
# => "fork"
puts common_substring(%w[ fork forks ]).inspect
# => "fork"

Mise à jour: Si le golf est le jeu ici, alors 67 caractères:

def f(d)d.inject{|m,s|s[0,(0..m.size).find{|i|m[i]!=s[i]}.to_i]}end
2
tadman

En lisant ces réponses avec toute la programmation fonctionnelle de fantaisie, le tri et les expressions rationnelles et ainsi de suite, je me suis juste dit: qu'est-ce qui ne va pas un petit C? Voici donc un petit programme loufoque.

#include <stdio.h>

int main (int argc, char *argv[])
{
  int i = -1, j, c;

  if (argc < 2)
    return 1;

  while (c = argv[1][++i])
    for (j = 2; j < argc; j++)
      if (argv[j][i] != c)
        goto out;

 out:
  printf("Longest common prefix: %.*s\n", i, argv[1]);
}

Compilez-le, exécutez-le avec votre liste de chaînes comme arguments de ligne de commande, puis votez pour l'utilisation de goto!

2
skagedal
Python 2.6 (r26:66714, Oct  4 2008, 02:48:43) 

>>> a = ['interspecies', 'interstelar', 'interstate']

>>> print a[0][:max(
        [i for i in range(min(map(len, a))) 
            if len(set(map(lambda e: e[i], a))) == 1]
        ) + 1]

inters
  • i for i in range(min(map(len, a))), le nombre de recherches maximum ne peut pas être supérieur à la longueur de la chaîne la plus courte; dans cet exemple, cela équivaudrait à [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

  • len(set(map(lambda e: e[i], a))), 1) créez un tableau du caractère i-th pour chaque chaîne de la liste; 2) en faire un ensemble; 3) déterminer la taille de l'ensemble

  • [i for i in range(min(map(len, a))) if len(set(map(lambda e: e[i], a))) == 1], n'inclut que les caractères pour lesquels la taille de l'ensemble est 1 (tous les caractères à cette position étaient les mêmes ..); ici, il serait évalué à [0, 1, 2, 3, 4, 5]

  • enfin prenez le max, ajoutez-en un, et obtenez la sous-chaîne ...

Remarque: ce qui précède ne fonctionne pas pour a = ['intersyate', 'intersxate', 'interstate', 'intersrate'], Mais cela:

 >>> index = len(
         filter(lambda l: l[0] == l[1], 
             [ x for x in enumerate(
                 [i for i in range(min(map(len, a))) 
                     if len(set(map(lambda e: e[i], a))) == 1]
         )]))
 >>> a[0][:index]
 inters
2
miku

Solution JS golfée juste pour le plaisir:

w=["hello", "hell", "helen"];
c=w.reduce(function(p,c){
    for(r="",i=0;p[i]==c[i];r+=p[i],i++){}
    return r;
});
1
Dan Prince

Voici une solution efficace dans Ruby. J'ai basé l'idée de la stratégie d'un jeu de devinettes hi/lo où vous vous concentrez itérativement sur le préfixe le plus long.

Quelqu'un me corrige si je me trompe, mais je pense que la complexité est O (n log n), où n est la longueur de la chaîne la plus courte et le nombre de chaînes est considéré comme une constante.

def common(strings)
  lo = 0
  hi = strings.map(&:length).min - 1
  return '' if hi < lo

  guess, last_guess = lo, hi

  while guess != last_guess
    last_guess = guess
    guess = lo + ((hi - lo) / 2.0).ceil

    if strings.map { |s| s[0..guess] }.uniq.length == 1
      lo = guess
    else
      hi = guess
    end
  end

  strings.map { |s| s[0...guess] }.uniq.length == 1 ? strings.first[0...guess] : ''
end

Et quelques vérifications que cela fonctionne:

>> common %w{ interspecies interstelar interstate }
=> "inters"

>> common %w{ dog dalmation }
=> "d"

>> common %w{ asdf qwerty }
=> ""

>> common ['', 'asdf']
=> ""
1
Ben Lee

Au lieu de trier, vous pouvez simplement obtenir le min et le max des chaînes.

Pour moi, l'élégance dans un programme informatique est un équilibre entre rapidité et simplicité. Il ne doit pas faire de calcul inutile et il doit être suffisamment simple pour rendre son exactitude évidente.

Je pourrais appeler la solution de tri "intelligente", mais pas "élégante".

1
Florian F

Alternative amusante Ruby solution:

def common_prefix(*strings)
  chars  = strings.map(&:chars)
  length = chars.first.Zip( *chars[1..-1] ).index{ |a| a.uniq.length>1 }
  strings.first[0,length]
end

p common_prefix( 'foon', 'foost', 'forlorn' ) #=> "fo"
p common_prefix( 'foost', 'foobar', 'foon'  ) #=> "foo"
p common_prefix( 'a','b'  )                   #=> ""

Cela peut aider à accélérer si vous utilisez chars = strings.sort_by(&:length).map(&:chars), car plus la première chaîne est courte, plus les tableaux créés par Zip sont courts. Cependant, si vous vous souciez de la vitesse, vous ne devriez probablement pas utiliser cette solution de toute façon. :)

1
Phrogz

Ma solution en Java:

public static String compute(Collection<String> strings) {
    if(strings.isEmpty()) return "";
    Set<Character> v = new HashSet<Character>();
    int i = 0;
    try {
        while(true) {
            for(String s : strings) v.add(s.charAt(i));
            if(v.size() > 1) break;
            v.clear();
            i++;
        }
    } catch(StringIndexOutOfBoundsException ex) {}
    return strings.iterator().next().substring(0, i);
}
1
fferri

Je ferais ce qui suit:

  1. Prenez la première chaîne du tableau comme initiale sous-chaîne de départ.
  2. Prenez la chaîne suivante du tableau et comparez les caractères jusqu'à ce que la fin de l'une des chaînes soit atteinte ou qu'une incompatibilité soit trouvée. Si une non-concordance est trouvée, réduisez sous-chaîne de départ à la longueur où la non-concordance a été trouvée.
  3. Répétez l'étape 2 jusqu'à ce que toutes les chaînes aient été testées.

Voici une implémentation JavaScript:

var array = ["interspecies", "interstelar", "interstate"],
    prefix = array[0],
    len = prefix.length;
for (i=1; i<array.length; i++) {
    for (j=0, len=Math.min(len,array[j].length); j<len; j++) {
        if (prefix[j] != array[i][j]) {
            len = j;
            prefix = prefix.substr(0, len);
            break;
        }
    }
}
1
Gumbo

Voici une solution utilisant des expressions régulières dans Ruby:

def build_regex(string)
  arr = []
  arr << string.dup while string.chop!
  Regexp.new("^(#{arr.join("|")})")
end

def substring(first, *strings)
  strings.inject(first) do |accum, string|
    build_regex(accum).match(string)[0]
  end
end
1
Yehuda Katz

Souvent, il est plus élégant d'utiliser une bibliothèque open source mature au lieu de rouler la vôtre. Ensuite, s'il ne répond pas complètement à vos besoins, vous pouvez l'étendre ou le modifier pour l'améliorer, et laisser la communauté décider si cela appartient à la bibliothèque.

diff-lcs est une bonne gemme Ruby pour la sous-chaîne la moins courante).

1
Grant Hutchins

Ma solution Javascript:

IMOP, l'utilisation du tri est trop délicate. Ma solution consiste à comparer lettre par lettre en bouclant le tableau. Renvoie une chaîne si la lettre n'est pas remplacée.

Voici ma solution:

var longestCommonPrefix = function(strs){
    if(strs.length < 1){
        return '';
    }

    var p = 0, i = 0, c = strs[0][0];

    while(p < strs[i].length && strs[i][p] === c){
        i++;
        if(i === strs.length){
            i = 0;
            p++;
            c = strs[0][p];
        }
    }

    return strs[0].substr(0, p);
};
0
Eric Chen

Rubis

require 'abbrev'

ar = ["interspecies", "interstelar", "interstate"]
ar.abbrev.keys.min_by(&:size).chop # => "inters"

Étant donné un ensemble de chaînes, abbrev calcule l'ensemble des abréviations non ambiguës pour ces chaînes et renvoie un hachage où les clés sont toutes les abréviations possibles (et les valeurs sont les chaînes complètes). La clé la plus courte moins la dernière char sera le préfixe commun.

0
steenslag

Ce n'est en aucun cas élégant, mais si vous voulez être concis:

Rubis, 71 caractères

def f(a)b=a[0];b[0,(0..b.size).find{|n|a.any?{|i|i[0,n]!=b[0,n]}}-1]end

Si vous voulez que cela se déroule, cela ressemble à ceci:

def f(words)
  first_Word = words[0];
  first_Word[0, (0..(first_Word.size)).find { |num_chars|
    words.any? { |Word| Word[0, num_chars] != first_Word[0, num_chars] }
  } - 1]
end
0
Jordan Running

Réalisant le risque que cela se transforme en une correspondance de code golf (ou est-ce l'intention?), Voici ma solution en utilisant sed, copiée de ma réponse à un autre SO question et raccourci à 36 caractères (dont 30 sont l'expression réelle sed). Il s'attend à ce que les chaînes (chacune sur une ligne distincte) soient fournies en standard entrée ou dans des fichiers passés comme arguments supplémentaires.

sed 'N;s/^\(.*\).*\n\1.*$/\1\n\1/;D'

Un script avec sed dans la ligne Shebang pèse 45 caractères:

#!/bin/sed -f
N;s/^\(.*\).*\n\1.*$/\1\n\1/;D

Une exécution de test du script (nommé longestprefix), avec des chaînes fournies en tant que "document ici":

$ ./longestprefix <<EOF
> interspecies
> interstelar
> interstate
> EOF
inters
$
0
ack

Ce n'est pas du golf de code, mais vous avez demandé quelque chose d'élégant, et j'ai tendance à penser que la récursivité est amusante. Java.

/** Recursively find the common prefix. */
public String findCommonPrefix(String[] strings) {

    int minLength = findMinLength(strings);

    if (isFirstCharacterSame(strings)) {
        return strings[0].charAt(0) + findCommonPrefix(removeFirstCharacter(strings));
    } else {
        return "";
    }
}

/** Get the minimum length of a string in strings[]. */
private int findMinLength(final String[] strings) {
    int length = strings[0].size();
    for (String string : strings) {
        if (string.size() < length) {
            length = string.size();
        }
    }
    return length;
}

/** Compare the first character of all strings. */
private boolean isFirstCharacterSame(String[] strings) {
    char c = string[0].charAt(0);
    for (String string : strings) {
        if (c != string.charAt(0)) return false;
    }

    return true;
}

/** Remove the first character of each string in the array, 
    and return a new array with the results. */
private String[] removeFirstCharacter(String[] source) {
    String[] result = new String[source.length];
    for (int i=0; i<result.length; i++) {
        result[i] = source[i].substring(1); 
    }
    return result;
}
0
Dean J

A Ruby version basée sur l'algorithme de @ Svante. Fonctionne ~ 3 fois plus vite que mon premier.

 def common_prefix set 
   i=0
   rest=set[1..-1]
   set[0].each_byte{|c|
     rest.each{|e|return set[0][0...i] if e[i]!=c}
     i+=1
   }
   set
 end
0
AShelly

Javascript clone de AShelly excellente réponse.

A besoin Array#reduce qui n'est pris en charge que dans Firefox.

var strings = ["interspecies", "intermediate", "interrogation"]
var sub = strings.reduce(function(l,r) { 
    while(l!=r.slice(0,l.length)) {  
        l = l.slice(0, -1);
    }
    return l;
});
0
Chetan Sastry