2017-01-02 65 views
3

所以我想寫一個函數返回所有素數的總和,直到包括一個提供的數字。嵌套ES6數組幫助器方法來生成素數數組

我寫了這個,它的工作原理:

function sumPrimes(num) { 
 
    const arr = Array.from({length: num+1}, (v, k) => k).slice(2); 
 
    return arr.filter(element => { 
 
    \t for(let i = 2; i < element; i++) { 
 
      if(element % i === 0) { 
 
       return false; 
 
      } 
 
     } 
 
     return element; 
 
    }).reduce((previous, current) => { 
 
    \t return previous += current; 
 
    }, 0); 
 
} 
 

 
sumPrimes(9);

我想這會看起來更整潔,如果for循環與另一個陣列的輔助方法所取代。然而,我正在努力實現這一點。

這是我到目前爲止有:

function sumPrimes(num) { 
 
    const arr = Array.from({length: num+1}, (v, k) => k).slice(2); 
 
    return arr.filter(element => { 
 
    \t return arr.find(ref => { 
 
     console.log("(" + element + " % " + ref + " === 0) " + (element % ref === 0)); 
 
    \t if(element % ref === 0) { return false; } 
 
     return true; 
 
    }); 
 
    }).reduce((previous, current) => { 
 
    \t return previous += current; 
 
    }, 0); 
 
} 
 

 
sumPrimes(20);

這樣寫的,功能不再按預期工作 - 它並不過濾任何數字的,因此所有由.reduce幫手加總。控制檯使它看起來像if語句仍然按照需要工作;我究竟做錯了什麼?

+0

不是你問什麼,但對於'(讓我= 2;我

+0

' wiki/Sieve_of_Sundaram)作爲你的幫手。 [這裏](http://jsfiddle.net/py3Qv/)是一個JS代碼。 – Redu

+0

謝謝@WillNess!我認爲沒有必要擔心平方根,但現在想想它,你可以說,我可以看到它是如何使功能更有效率 –

回答

2

您的代碼無法使用find的原因是因爲find不適合替換您的for循環。您在此處的for循環將返回一個布爾值,指示是否找到除數。另一方面,find返回除數本身。這意味着你的filter方法的所有條件都是大於1的數字,所有這些都被評估爲真實,因此沒有任何過濾。

更適合您的使用案例的方法是someevery。 這些基本上像find一樣工作,但只要他們找到滿足條件的元素就返回一個布爾值。

  • some停止,只要斷言功能對於一些元素返回true返回true。否則返回false

  • every停止並返回false一旦謂詞函數返回某個元素的false。 否則它返回true

還有一個問題是,使用這樣的幫手,使你的代碼效率不高,因爲你現在正在檢查所有的數字,而不是僅僅上漲到目前的數量。這意味着你的謂詞函數也必須包含這個相等性檢查,否則你將不得不首先對被檢查元素下面的所有元素進行過濾。

效率方面的另一個小改進是,您不需要一直迭代到element - 1以查找除數。迭代到sqrt(element)就足夠了,因爲所有高於sqrt(element)的數字將會在下面的某個地方有一個補碼除數sqrt(element)

下面是使用every並過濾被檢查元素的平方根以下元素的方法。

function sumPrimes(num) { 
 
    const arr = Array.from({length: num+1}, (v, k) => k).slice(2); 
 
    return arr.filter(element => { 
 
    return arr 
 
     .filter(ref => ref*ref <= element) // filter elements less than sqrt(current) 
 
     .every(ref => element % ref !== 0); // filter elements that have a divisor 
 
    }).reduce((previous, current) => { 
 
    return previous += current; 
 
    }, 0); 
 
} 
 

 
console.log(sumPrimes(9)); // 17

也許一個功能比較少,但更有效的(恕我直言同樣乾淨)的方式是隻將您for循環到一個輔助功能:

function isPrime(element) { 
 
    for(let i = 2; i*i <= element; i++) { 
 
    if(element % i === 0) { 
 
     return false; 
 
    } 
 
    } 
 
    return true; 
 
} 
 

 
function sumPrimes(num) { 
 
    return Array 
 
    .from({ length: num+1 }, (v, k) => k) 
 
    .slice(2) 
 
    .filter(isPrime) 
 
    .reduce((previous, current) => previous += current, 0); 
 
} 
 

 
console.log(sumPrimes(9)); // 17

+0

沒問題matw,很高興幫助 – nem035

+0

謝謝!這真的很有幫助。 –

+0

因此第二個.filter是必需的,否則.every函數將簡單地遍歷數組中的所有元素,超出父過濾器函數的當前元素。 是的,我確實發現你提出的第二種解決方案實際上更容易閱讀,謝謝!我有一種感覺,我可能會過度... –

3

您可以減少pri的研究範圍在開方的ñ mality(N):

var isPrime = n => n===2 ? true : Array(Math.ceil(Math.sqrt(n))+1).fill().map((e,i)=>i).slice(2).every(m => n%m); 
 
    
 
var sumPrimes = num => Array(num).fill().map((e,i)=>i+1).slice(1).filter(isPrime).reduce((a,b) => a+b); 
 

 
console.log(sumPrimes(9));

+0

質數達9的總和應爲17:(2 + 3 + 5 + 7) – nem035

+1

@ nem035我剛剛修復了這個錯誤。感謝您的測試 –