Testowanie, czy wartość jest nieparzysta czy parzysta


173

Postanowiłem stworzyć proste funkcje isEven i isOdd z bardzo prostym algorytmem:

function isEven(n) {
  n = Number(n);
  return n === 0 || !!(n && !(n%2));
}

function isOdd(n) {
  return isEven(Number(n) + 1);
}

To jest OK, jeśli n ma określone parametry, ale w wielu scenariuszach kończy się niepowodzeniem. Postanowiłem więc stworzyć solidne funkcje, które dostarczają poprawne wyniki dla tak wielu scenariuszy, jak tylko mogłem, tak aby testowane były tylko liczby całkowite w granicach liczb javascript, a wszystko inne zwraca fałsz (w tym + i - nieskończoność). Zauważ, że zero jest parzyste.

// Returns true if:
//
//    n is an integer that is evenly divisible by 2
//
// Zero (+/-0) is even
// Returns false if n is not an integer, not even or NaN
// Guard against empty string

(function (global) {

  function basicTests(n) {

    // Deal with empty string
    if (n === '') 
      return false;

    // Convert n to Number (may set to NaN)
    n = Number(n);

    // Deal with NaN
    if (isNaN(n)) 
      return false;

    // Deal with infinity - 
    if (n === Number.NEGATIVE_INFINITY || n === Number.POSITIVE_INFINITY)
      return false;

    // Return n as a number
    return n;
  }

  function isEven(n) {

    // Do basic tests
    if (basicTests(n) === false)
      return false;

    // Convert to Number and proceed
    n = Number(n);

    // Return true/false
    return n === 0 || !!(n && !(n%2));
  }
  global.isEven = isEven;

  // Returns true if n is an integer and (n+1) is even
  // Returns false if n is not an integer or (n+1) is not even
  // Empty string evaluates to zero so returns false (zero is even)
  function isOdd(n) {

    // Do basic tests
    if (basicTests(n) === false)
      return false;

    // Return true/false
    return n === 0 || !!(n && (n%2));
  }
  global.isOdd = isOdd;

}(this));

Czy ktoś widzi jakieś problemy z powyższym? Czy istnieje lepsza (tj. Dokładniejsza, szybsza lub bardziej zwięzła bez zaciemniania) wersja?

Istnieje wiele postów dotyczących innych języków, ale nie mogę znaleźć ostatecznej wersji ECMAScript.


Odpowiedzi:


368

Użyj modułu:

function isEven(n) {
   return n % 2 == 0;
}

function isOdd(n) {
   return Math.abs(n % 2) == 1;
}

Możesz sprawdzić, czy dowolna wartość w JavaScript może zostać przekształcona w liczbę za pomocą:

Number.isFinite(parseFloat(n))

Najlepiej, aby to sprawdzenie było wykonywane poza funkcjami isEveni isOdd, aby nie trzeba było powtarzać obsługi błędów w obu funkcjach.


@Steve Tak, ale JS ma pewne specjalne problemy, gdy valuenie jest liczbą lub nawet jeśli jest liczbą. Np .: 0.1%2, NaN%2, []%2, itd. To, co napisałem w odpowiedzi, on już wie.
Alin Purcaru

1
0.1i NaNdziała dobrze z powyższą funkcją. Pusta tablica jest trochę uciążliwa, ponieważ równa się 0 ...
Steve Mayne

4
@Alin - dodałem kontrolę numeryczną. Nie jestem pewien, czy rozumiem scenariusz, w którym chcesz, aby funkcja arytmetyczna jawnie obsługiwała inne typy danych, ale jeśli tego chce OP ...
Steve Mayne

2
A co ze zmianą return n == parseInt(n);na return n === parseInt(n);?
JiminP

2
Chyba gdzieś przeczytałem, co powinieneś sprawdzić n % 2 !== 0sprawdzając liczby nieparzyste, ponieważ niekoniecznie jest to 1, w zależności od języka. EDYCJA: Ach, po to jest .abswezwanie. Nieważne więc.
ptf

79

Wolę używać testu bitowego:

if(i & 1)
{
    // ODD
}
else
{
    // EVEN
}

To sprawdza, czy pierwszy bit oznacza liczbę nieparzystą.


Przydatne tylko wtedy, gdy wiesz, że ja jest liczbą na początek. Nie-liczby powinny zwracać undefined (lub może generować błąd, ale undefined wydaje się sensowne).
RobG

3
Absolutnie. Używanie modułu do matematyki o podstawie 2 powinno być nielegalne;)
aceofspades

4
Ternary: i & 1 == 1 ? console.log("odd") : console.log("even");Również +1 za wydajność poziomu bitów (nie tak szeroko stosowane w JS)
Jacksonkr

13
@Jacksonkr Zauważ, że w JavaScript nie ma „wydajności na poziomie bitowym”, ponieważ wszystkie liczby są zmiennoprzecinkowe w JavaScript, a użycie operatora bitowego oznacza najpierw konwersję go na liczbę int, a następnie wykonanie operacji, a następnie konwersję z powrotem na liczbę zmiennoprzecinkową.
poke

1
@poke Prawidłowo są typu Number, ale miło jest wiedzieć, że w językach silnie wpisywanych jest wydajność.
Robert Brisita

8

A co z następującymi? Testowałem to tylko w IE, ale z przyjemnością radziłem sobie z ciągami reprezentującymi liczby dowolnej długości, rzeczywistymi liczbami, które były liczbami całkowitymi lub zmiennoprzecinkowymi, a obie funkcje zwracały fałsz po przekazaniu wartości logicznej, niezdefiniowanej, null, tablicy lub obiektu. (Od Ciebie zależy, czy chcesz ignorować początkowe lub końcowe spacje, gdy przekazywany jest ciąg - założyłem, że nie są one ignorowane i powodują, że obie funkcje zwracają fałsz).

function isEven(n) {
   return /^-?\d*[02468]$/.test(n);
}

function isOdd(n) {
   return /^-?\d*[13579]$/.test(n);
}

2
W mojej implementacji isEven (2.122e3) zwraca wartość true, ale isEven („2.122e3”) zwraca wartość false. I odwrotnie, moja isEven () nie działa w przypadku naprawdę dużych liczb, ponieważ JS umieszcza je w formacie wykładnika podczas konwersji na ciąg znaków dla testu regex. No cóż.
nnnnnn

@MartijnScheffer - Zapraszam do przesłania mi rachunku za całą dodatkową pamięć, którą będziesz musiał kupić. Zwróć uwagę, że pytanie obejmowało konwersje z innych typów na liczby i wyraźnie sugeruję, że chodzi o prostą jednowierszową funkcję, która obsługuje liczby i ciągi. Oczywiście, zgodnie z moim komentarzem, nie obsługuje to wszystkich możliwych przypadków, ale nadal może być przydatne - regex jest najprostszym sposobem sprawdzenia poprawności danych wprowadzonych przez użytkownika, które początkowo będą ciągiem znaków.
nnnnnn

czy opublikowałem tutaj komentarz? nie widzę tego, ale mogę, jeśli chcesz!, to NIE jest poprawne rozwiązanie, jest to setki razy wolniejsze, a mówimy o liczbach, a nie łańcuchach, jeśli chcesz sprawdzić, czy ciąg jest prawidłowy liczba i liczba całkowita, którą można obsługiwać osobno.
Martijn Scheffer

@MartijnScheffer - Tak, był od Ciebie komentarz, wydaje się, że został usunięty w pewnym momencie od mojej odpowiedzi. Zwróć uwagę, że pytanie nie dotyczyło tylko liczb, kod OP zawierał konwersje z innych typów. W każdym razie dziękuję za twoją opinię.
nnnnnn

7

Uwaga: istnieją również liczby ujemne.

function isOddInteger(n)
{
   return isInteger(n) && (n % 2 !== 0);
}

gdzie

function isInteger(n)
{
   return n === parseInt(n, 10);
}

1
Czy nie parseInt potrzebuje tutaj podstawy?
blablabla

@blablabla Tak, nie wszystkie implementacje zakładają radix = 10.
Rodrigo

Dobre cytowanie wartości ujemnych. Odpowiedź Roberta Brisity (która została dodana później) również to obejmuje.
Jacksonkr

4

Dlaczego po prostu tego nie zrobić:

    function oddOrEven(num){
        if(num % 2 == 0)
            return "even";
        return "odd";
    }
    oddOrEven(num);

Lub nawet function isEven(num) { return num % 2 == 0}
chiapa,

3
lub z ES6:const oddOrEven = num => num % 2 === 0 ? 'even' : 'odd'
enguerran


1
var isEven = function(number) {
    // Your code goes here!
    if (number % 2 == 0){
       return(true);
    }
    else{
       return(false);    
    }
};

2
if ( <expression> ) return true else return falseParadygmat może zawsze być uproszczone return ( <expression> )(od ekspresji w if już jest zawsze jedna logiczna).
Gerold Broser

mówienie, że zwrot nie jest funkcją, jest jak mówienie, że jeśli nie jest funkcją, to całkowicie poprawne jest użycie nawiasów podczas zwracania wartości (nawet jeśli nie są one tutaj przydatne)
Martijn Scheffer

1

Prosta modyfikacja / ulepszenie odpowiedzi Steve Mayne!

function isEvenOrOdd(n){
    if(n === parseFloat(n)){
        return isNumber(n) && (n % 2 == 0);
    }
    return false;
}

Uwaga: zwraca fałsz, jeśli jest nieprawidłowy!


1

Potrzebujemy do tego tylko jednej linii kodu!

Tutaj nowsza i alternatywny sposób to zrobić, korzystając z nowego ES6 składnię funkcji JS i składni jednej linii dla if-elsewywołania instrukcji:

const isEven = num => ((num % 2) == 0) ? true : false;

alert(isEven(8));  //true
alert(isEven(9));  //false
alert(isEven(-8)); //true

1
Który jest krótszy jak let isEven = num => num % 2 === 0. :-) Ale tak naprawdę nie różni się od wielu innych odpowiedzi tutaj.
RobG

1

Kilka

x % 2 == 0; // Check if even

!(x & 1); // bitmask the value with 1 then invert.

((x >> 1) << 1) == x; // divide value by 2 then multiply again and check against original value

~x&1; // flip the bits and bitmask

0

Inny sposób:

var isEven = function(number) {
  // Your code goes here!
  if (((number/2) - Math.floor(number/2)) === 0) {return true;} else {return false;};
};

isEven(69)

0

W przeciwnym razie używa się ciągów, ponieważ dlaczego nie

function isEven(__num){
    return String(__num/2).indexOf('.') === -1;
}

0
if (testNum == 0);
else if (testNum % 2  == 0);
else if ((testNum % 2) != 0 );

Bez wyjaśnienia Twój wkład nie ma dużej wartości. Powtarza również informacje, które zostały już przedstawione w dyskusji.
Cindy Meister

Dzięki Cindy! Oferuję tylko rozwiązanie!
Lindsay

Ale ... to właściwie nic nie robi . Czy nie powinno coś zwrócić?
nnnnnn

0

Może to? if (naszNumer% 2! == 0)


2
Chociaż ten fragment kodu może rozwiązać problem, dołączenie wyjaśnienia naprawdę pomaga poprawić jakość Twojego posta. Pamiętaj, że odpowiadasz na pytanie do czytelników w przyszłości, a osoby te mogą nie znać powodów, dla których zaproponowałeś kod. Prosimy również starać się nie zatłaczać kodu komentarzami wyjaśniającymi, co zmniejsza czytelność zarówno kodu, jak i wyjaśnień!
Filnor

0
var num = someNumber
    isEven;
parseInt(num/2) === num/2 ? isEven = true : isEven = false;

0

for(var a=0; a<=20;a++){
   if(a%2!==0){
       console.log("Odd number "+a);
   }
}

for(var b=0; b<=20;a++){
    if(b%2===0){
        console.log("Even number "+b);  
    }     
 }


Chociaż ten kod może rozwiązać problem, w tym wyjaśnienie, jak i dlaczego to rozwiązuje problem, naprawdę pomogłoby poprawić jakość twojego posta i prawdopodobnie zaowocowałoby większą liczbą pozytywnych głosów. Pamiętaj, że odpowiadasz na pytanie do czytelników w przyszłości, a nie tylko osoba, która zapyta teraz. Proszę edytować swoje odpowiedzi, aby dodać wyjaśnień i dać wskazówkę co zastosować ograniczenia i założenia.
Daniil

-1

Aby sprawdzić, czy masz liczbę nieparzystą lub parzystą, to również działa.

const comapare = x => integer(checkNumber(x));

function checkNumber (x) {
   if (x % 2 == 0) {
       return true;
   } 
   else if (x % 2 != 0) {
       return false;
    }
}

function integer (x) {
   if (x) {
       console.log('even');
   } 
   else {
       console.log('odd');
    }
}

-1

Korzystanie z nowoczesnego stylu javascript:

const NUMBERS = "nul one two three four five six seven ocho nueve".split(" ")

const isOdd  = n=> NUMBERS[n % 10].indexOf("e")!=-1
const isEven = n=> isOdd(+n+1)

isOdd('5'))zwraca prawdę. isEven('5')również zwraca prawdę. isOdd(NaN)zgłasza błąd. :-(
RobG

Naprawiono isEven('5'). isOdd(NaN)prawdopodobnie powinien wyrzucić błąd.
gunn

1
Host skryptu nie powinien obsługiwać błędu, a funkcja powinna. Zawsze mówiono mi, że zrzut rdzenia nie jest normalnym zakończeniem . ;-)
RobG


-2
function isEven(n) {return parseInt(n)%2===0?true:parseInt(n)===0?true:false}

kiedy 0 / nawet chciał ale

isEven(0) //true
isEven(1) //false
isEven(2) //true
isEven(142856) //true
isEven(142856.142857)//true
isEven(142857.1457)//false

Wcześniejsze


Lub return parseInt(n)%2===0?true:parseInt(n)===0. ale z drugiej strony jest to to samo, co wiele innych odpowiedzi już tutaj.
Heretic Monkey

1
Lub return parseInt(n)%2 === 0 || parseInt(n) === 0. Ale dlaczego analizować ? To zwraca prawdę dla wartości takich jak „32foo” i 12.5, które nie są parzyste.
RobG,

-2
if (i % 2) {
return odd numbers
}

if (i % 2 - 1) {
return even numbers
}

1
kiedy przypomnienie o podzieleniu dowolnej liczby przez 2 wyniesie 2?
user85421

Hm, tak, masz rację. Tęsknię za napisaniem% 2 == 2. Moja wina.
Dejan Markovic
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.