2014-10-25 4 views
2

Что я хочу получить, это как clean([3,2,3,2,5,1]) == [5,1], для цели обучения я хочу сделать это с помощью рекурсивной функции и только для javascript ваниля. Функция я написал следующим образом:Использование рекурсивной функции для удаления всех дублированных элементов массива

r=[]; 
var clean = function(array){ 
    var s1=array.slice(0); 
    var s2=array.slice(0); 
    if(s2[0] !== undefined) { 
     r.push(s2.shift()); 
     for (i=0,flag=false;i<s2.length;i++){ 
      if (r[r.length-1] == s2[i]){ 
       s1[i+1]=undefined; 
       flag=true; 
      } 
     } 
     if (flag==true){ 
      r.pop(); 
      s1.shift(); 
      for (j=0;j<s1.length;j++){ 
       if (s1[j] == undefined) {s1.splice(j,1);j--}; 
      } 
     } 
     else{ 
      s1.shift(); 
     } 
    } 
    if (s2.length !== 0) clean(s1); 
    return; 
} 

Кажется, работает, но есть что-то я не чувствую себя комфортно:

Прежде всего, я новичок в программировании, когда я пишу javascript, я всегда чувствую необходимость определять переменную вне функции для хранения результата, так как r в этом случае, я знаю, что это очень плохая практика, и я должен определить переменную внутри функции и просто вернуть ее. Но я потратил 6 часов на написание выше кодов (не смейся над мной), теперь мой мозг полностью терпит неудачу, я не могу придумать способ привести эту переменную в функцию. Любые намеки приветствуются;

Во-вторых, когда я перебираю массив и изменяю его, его длина изменяется на ходу, делая цикл ненадежным, мне пришлось скопировать массив на 2 разные переменные (s1,s2), чтобы избежать проблемы с циклом. Это очень неудобно. Позже я думаю о том, что я могу изменить индекс цикла на ходу, пока длина массива изменяется (как вы можете видеть в цикле j), но является ли это хорошей практикой? Ниже улучшена функция кажется работает слишком:

var ccc = function(array){ 
    var s1=array.slice(0); 
    if(s1[0] !== undefined) { 
     r.push(s1.shift()); 
     for (i=0,flag=false;i<s1.length;i++){ 
      if (r[r.length-1] == s1[i]){ 
       s1.splice(i,1); 
       i--; 
       flag=true; 
      } 
     } 
     if (flag==true){ 
      r.pop(); 
     } 
     if (s1.length !== 0) ccc(s1); 
    } 
    return; 
} 

Кроме того, я знаю, JQuery, вероятно, имеет функцию для достижения этой цели, но если нет кадра не допускаются, что это лучший подход (рекурсивный или нет)? Я кратко просматриваю stackoverflow, но не нахожу точных ответов.

+0

Выполнение этого рекурсивно - плохая идея. Просто перебирайте список и удаляйте дубликаты, это намного более естественно. Я знаю, что вы сказали, что делаете это для учебных целей, но вы будете изучать нестандартные/плохие методы, которые делают это. – dursk

+1

Функция, которую вы написали, не является рекурсивной. –

+1

Была опечатка. Если вы имеете в виду опечатку, говоря, что функции не рекурсивные, я их отредактировал. Я думаю, что если функция вызывает себя, она рекурсивна, не так ли? – shenkwen

ответ

1

Это может быть значительно упрощено, на мой взгляд. В вашем коде есть флаги и много крутизны.

Вместо этого JavaScript-массивы уже поставляются с методами трансформации - один из таких методов для удаления элементов из массива, который вам не нужен, и возврата нового массива только с теми элементами, которые вы делаете, это .filter.

var clean = myArr.filter(function(el, i, arr){ 
    // filter the array 
    // if we return true from here - the element will stay, otherwise it won't 
    return (arr.indexOf(el) === i) && (arr.lastIndexOf(el) === i); 
}); 

В принципе, наш код говорит «первые и последние индексы элемента являются такими же, как этой» - это значит, есть только один элемент в массиве. Это не самый быстрый способ, но он довольно чистый, и производительность в любом случае не имеет значения для небольших массивов. Вы можете поместить его в функцию, конечно:

function clean(arr) { 
 
     return arr.filter(function(el, i) { 
 
     return (arr.indexOf(el) === i) && (arr.lastIndexOf(el) === i); 
 
     }); 
 
    } 
 
    alert(clean([3, 2, 3, 2, 5, 1]));

Что я считаю, намного короче, чище и читаемым, чем то, что вы начали. В ES6 (следующая версия спецификации JavaScript основана на) и делает это немного медленнее - это становится еще более чистым:

let clean = (arr) => arr.filter((el, i) => arr.indexOf(el) === arr.lastIndexOf(el)); 
alert(clean([3, 2, 3, 2, 5, 1])); 
+0

Не будет 'arr.indexOf (el) === arr.lastIndexOf (el)' быть чище? Соответствие 'i' является неявным, учитывая, что функция фильтра была вызвана в первую очередь. – Emissary

+0

@ Emissary да, но короткое замыкание сделало бы это также намного медленнее, так как потребовалось бы больше итераций в случае 'arr.indexOf (el) === i' –

+0

oh thanks - Мне казалось, что заглянул в последнюю часть вашего сообщения не заметив, что вы уже рассмотрели это:/ – Emissary

Смежные вопросы