Vinnaren i pepparkakshustävlingen!
2017-09-27, 20:41
  #1
Medlem
Worldnatures avatar
Hej! Här kör jag så jag retunerar ut koden från störst till lägst och sen lägst till störst. men nu är problemet, hur ska jag göra för att få ut mean? och även median i en sådan function som denna?

function maximum (numbers) {
let copy = numbers.slice()
copy.sort(function (a, b) {
return b - a
})
return copy[0]
}

function minimum (numbers) {
let copy1 = numbers.slice()
copy1.sort(function (a, b) {
return a - b
})
return copy1[0]
}
function mean (numbers) {
let copy2 = numbers.slice()
copy2.sort(function (a, b) {
return a - b

})
return copy2[0]
}
Citera
2017-09-27, 20:50
  #2
Medlem
Kod:
function sum(numbers) {
    return numbers.reduce((previousValue, currentValue) => {
        return previousValue + currentValue;
    }, 0);
}

function mean(numbers) {
    return sum(numbers) / numbers.length;
}
Citera
2017-09-28, 04:17
  #3
Medlem
xitunos avatar
Jag såg att du sorterade arrayen för att plocka ut det lägsta respektive högsta värdet. Att sortera en array är väldigt tidskrävane och (beroende på vilken algoritm som används) gås arrayen igenom flertalet gånger. Det är mycket effektivare att bara gå igenom arrayen EN gång, och hålla reda på vilket det lägsta respektive hösta värdet är.

Kod:
function minimum(values) {
  return values.reduce(
    (result, value) => { return result < value ? result : value; },
    values[0]
  );
};

Kod:
function maximum(values) {
  return values.reduce(
    (result, value) => { return result > value ? result : value; },
    values[0]
  );
};


För medelvärdet behövs det inte heller sorteras. Istället adderas alla tal och summan divideras med antalet tal (längden på arrayen).
Kod:
function mean(values) {
  return values.reduce(
    (result, value) => { return result + value; }, 0
  ) / values.length;
}

För medianvärdet behöver dock talen sorteras. Eftersom sorteringsfunktionen ändrar arrayen som den sorterar, måste en kopia först göras, så att det inte blir några sidoeffekter i övrig kod.
Kod:
function median(values) {
  // Copy array before sort, since sorting is made "in place" and change the array for the caller
  let sorted = values.slice(0).sort( (a,b) => { return a - b; } );
  let middle = Math.floor( sorted.length / 2 );
  // if length is odd then return middle, else return average of two elements
  return sorted.length & 1 ? sorted[middle]: (sorted[middle] + sorted[middle - 1]) / 2;
}


Sen har jag en viktig hjälpfunktion... De ovanstående funktionerna förutsätter att det är en endimensionell array med tal som fås som input. Då javascript är ett löst typat språk kan strängar och vissa andra objekt automatiskt konverteras till tal, vilket kan ge konstiga resultat. Exempelvis kommer mean att ge NaN som resultat om det finns en sträng som inte kan konverteras till nummer, medan minimum, maximum och median i många fall ignorerar det. Så innan du anropar någon av ovanstående funktioner, anropa isNumber
Kod:
function isNumber(values) {
  return Array.isArray(values) && values.length && values.every(
    (value) => { return typeof value === 'number'; }
  );
}

Du behöver bara verifiera att det är tal EN gång för varje array du ska plocka fram statistiken ifrån. Exempelvis så här:
Kod:
function getStatistic(values) {
  return isNumber(values) ? {
    minimum : minimum(values),
    maximum : maximum(values),
    mean : mean(values),
    median : median(values)
  } : null;
}
Citera
2017-09-28, 17:27
  #4
Medlem
xitunos avatar
Vid närmare eftertanke bör du använda isNumberFinite istället för isNumber som jag beskrev i tidigare inlägg. Anledningen är att isNumber ger ett sant svar även om talet är NaN (Not a Number) eller om det är Infinity eller -Infinity.

isNumberFinite ger bara sant svar om talen är ändliga, då isFinite ger falskt svar för både oändliga tal och NaN.
Kod:
function isNumberFinite(values) {
  return Array.isArray(values) && values.length && values.every(
    (value) => { return typeof value === 'number' && isFinite(value); }
  );
}

Om du har behov av att talen ska kunna vara Infinity eller -Infinity kan du istället använda isNumberValid, som ger sant svar om det är ett tal och talet inte är NaN.
Kod:
function isNumberValid(values) {
  return Array.isArray(values) && values.length && values.every(
    (value) => { return typeof value === 'number' && !isNaN(value); }
  );
}
Citera
2017-09-28, 23:26
  #5
Medlem
Povels avatar
Citat:
Ursprungligen postat av xituno
Jag såg att du sorterade arrayen för att plocka ut det lägsta respektive högsta värdet. Att sortera en array är väldigt tidskrävane och (beroende på vilken algoritm som används) gås arrayen igenom flertalet gånger. Det är mycket effektivare att bara gå igenom arrayen EN gång, och hålla reda på vilket det lägsta respektive hösta värdet är.

Kod:
function minimum(values) {
  return values.reduce(
    (result, value) => { return result < value ? result : value; },
    values[0]
  );
};

Kod:
function maximum(values) {
  return values.reduce(
    (result, value) => { return result > value ? result : value; },
    values[0]
  );
};

[...]

[/code]

Tips: man kan med fördel använda de befintliga `Math.min` resp. `Math.max` istället för att skriva egna funktioner för samma ändamål:

Kod:
const numbers = [1020125917101];
Math.min(...numbers); // 5
Math.max(...numbers); // 101 

Se https://developer.mozilla.org/en-US/...jects/Math/min och https://developer.mozilla.org/en-US/...jects/Math/max.

/p
Citera
2017-09-29, 09:30
  #6
Medlem
xitunos avatar
Citat:
Ursprungligen postat av Povel
Tips: man kan med fördel använda de befintliga `Math.min` resp. `Math.max` istället för att skriva egna funktioner för samma ändamål:

Jag är väl medveten om att den möjligheten finns, men jag använder avsiktligt inte den möjligheten eftersom att jag känner till dess begränsningar. Problemet med att använda de inbyggda funktionerna på det sätt du beskriver, med spread-operatorn är att varje element skickas som ett separat argument till funktionen. Javascript har en begränsning på hur många argument en funktion kan ta emot, så om arrayen är för stor blir resultatet inte det du förväntade dig.

Källa
Citat:
Spread with many values

When using spread syntax for function calls, be aware of the possibility of exceeding the JavaScript engine's argument length limit. See apply() for more details.

Källa
Citat:
But beware: in using apply this way, you run the risk of exceeding the JavaScript engine's argument length limit. The consequences of applying a function with too many arguments (think more than tens of thousands of arguments) vary across engines (JavaScriptCore has hard-coded argument limit of 65536), because the limit (indeed even the nature of any excessively-large-stack behavior) is unspecified. Some engines will throw an exception. More perniciously, others will arbitrarily limit the number of arguments actually passed to the applied function.

Exempel som kraschar både i Chrome och Firefox:
Kod:
let data=[];
for (let i=0; i < 1000000; i+=1) data[i] = 10;
Math.min(...data);

Chrome ger RangeError: Maximum call stack size exceeded och Firefox RangeError: too many function arguments.
Citera

Stöd Flashback

Flashback finansieras genom donationer från våra medlemmar och besökare. Det är med hjälp av dig vi kan fortsätta erbjuda en fri samhällsdebatt. Tack för ditt stöd!

Stöd Flashback