Javascript adding to an interval of an array - javascript

Let's say that I have an array var x = [1, 2, 3, 4], and I would like to add 1 to the second and the third element of the array. In Python numpy I could do x[1:3] += 1 to add to the interval from 1st to 3rd (3rd excluded) element of x. Is there a similar method in JavaScript?

You could take a function with a closure
const
map = (start, end, fn) => (v, i) => i >= start && i <= end ? fn(v) : v,
x = [1, 2, 3, 4],
result = x.map(map(1, 2, v => v + 1));
console.log(result);

It's hard to beat python on this, but how about golang? Here's a quick POC:
function _toInt(s, def = null) {
try {
let n = Number(s);
return Number.isInteger(n) ? n : def;
} catch {
return def;
}
}
class _Slice {
constructor(ary, idx) {
this.ary = ary;
let ii = idx.split(':');
this.start = _toInt(ii[0], 0);
this.end = _toInt(ii[1], ary.length);
this.step = _toInt(ii[2], 1);
}
get(obj, p) {
let n = _toInt(p);
if (n === null)
return this[p];
let k = this.start + n * this.step;
return this.ary[k];
}
set(obj, p, val) {
let n = _toInt(p);
if (n === null)
return this[p] = val;
let k = this.start + n * this.step;
return this.ary[k] = val;
}
* [Symbol.iterator]() {
for (let i = 0, k = this.start; k < this.end; k += this.step, i++) {
yield [i, this.ary[k]]
}
}
}
let Slice = (ary, idx) => new Proxy([], new _Slice(ary, idx));
//
let array = [0, 11, 22, 33, 44, 55, 66, 77, 88, 99]
let slice = Slice(array, '1:8:2')
for (let [i, _] of slice)
slice[i] *= 100;
console.log(array)
With some more love, this should allow us to do
Slice([1,2,3,4,5,6])['1::4'] = 9 // [1,9,9,9,5,6]
Slice([1,2,3,4,5,6])['1::4'] = [7, 8, 9] // [1,7,8,9,5,6]
and of course
Slice([1,2,3,4,5,6])['::-1'] // [6,5,4,3,2,1]

Related

Find unique number in unsorted array JavaScript

I have to find a unique number in unsorted array, but my function returns wrong number, I can't understand why.
Here is my code:
function findUniq(arr) {
let sorted = [...arr].sort();
if (sorted.length === 0) return 0;
// do magic
let num = 0;
for (let i = 1; i < sorted.length; i++) {
if (sorted[num] !== sorted[i]) {
num++;
sorted[num] = sorted[i];
}
}
return num + 1;
}
const testArray = [9, 7, 7, 9, 6, 6, 5, 5, 5];
console.log(findUniq(testArray));
if I invoke findUniq([9,7,7,6,6,5,5,5]) it gives 4. What do I do wrong? Thanks in advance. I forgot to mention I have to have just one for loop to implement O(n) time complexity
I don't know why your solution doesn't work, but here is working code:
const arr = [9,9,7,7,8,6,1,6,5,5,5]
function findUnique(arr){
const sorted = [...arr].sort()
if(sorted[0] !== sorted[1]) return sorted[0]
if(sorted[sorted.length - 1] !== sorted[sorted.length - 2]) return sorted[sorted.length - 1]
for(let i = 0; i < sorted.length; i++){
if(sorted[i] !== sorted[i - 1] && sorted[i] !== sorted[i + 1]) return sorted[i]
}
return "no unique"
}
console.log(findUnique(arr))
This should work:
It returns only one unique number in array or undefined
If you want all unique numbers replace return arr[0] with return arr. It will then return array of all unique numbers (or empty array if there are not any)
function findUniq(arr) {
arr.filter((item, index) => {
arr.splice(index, 1)
const unique = !arr.includes(item)
arr.splice(index, 0, item)
return unique
})
return arr[0]
}
ES6 aproach:
function findUniq(arr) {
return arr
.map((c) => arr.filter((b) => c == b))
.filter((e) => e.length < 2)
.reduce((total, cur) => total.concat(cur), [])
}
You can use reduce and can find the item that repeats once in the last index.
var arr = [9,7,7,6,6,5,5,5]
var uniqueNumber;
arr.reduce((obj,val,index) =>
{
obj[val] ? ++obj[val] : obj[val] = 1;
if(index == (arr.length - 1))
{
uniqueNumber = Object.keys(obj).find(key => obj[key] === 1)
}
return obj
},{})
console.log(uniqueNumber)
To do it in a single O(n) loop, reduce, keeping track of counts as well as a set of singular items.
function findUniq(arr) {
let [single] = arr.reduce((acc, el) => {
if (!acc[el]) acc[el] = 0;
if (++acc[el] === 1) acc.singular.add(el);
else acc.singular.delete(el);
return acc;
}, { singular: new Set() }).singular;
return single;
}
const input = [2, 2, 9, 7, 7, 6, 6, 5, 5, 5];
const result = findUniq(input);
console.log(result);

trying to find element of array from which sum of left side of array is equal to sum of right side of array in JavaScript

I am trying to find element of array from which sum of left side of array is equal to sum of right side of array in JavaScript
I am using:
function findEvenIndex(arr)
{
//Code goes here!
let num = 0;
function check(i){
console.log(arr);
console.log(num)
let arrPart1 = arr.slice(0,i).reduce(((a,b)=>a+b),0);
console.log(arrPart1)
let arrPart2 = arr.slice(i+1,arr.length).reduce(((c,d)=>c+d),0);
console.log(arrPart2)
if(arrPart2 === 0){
return -1
}
else if(arrPart1 !== arrPart2){
num++;
check(num);
}
}
return check(num);
}
For array:
[1,100,50,-51,1,1]
Getting:
[ 1, 100, 50, -51, 1, 1 ]
0
0
101
[ 1, 100, 50, -51, 1, 1 ]
1
1
1
Error:
The array was: [1,100,50,-51,1,1]
: expected undefined to equal 1
I'd recommend abandoning the recursive solution and opting for an iterative one - in this situation, it's easier to debug. I've written a function that is easy to understand and can solve your problem here:
function findEvenIndex(arr)
{
for(let i = 0; i < arr.length; i++) {
let leftTotal = arr.slice(0, i).reduce((t, v) => t + v, 0);
let rightTotal = arr.slice(i + 1).reduce((t, v) => t + v, 0);
if (leftTotal === rightTotal) {
return i;
}
}
return -1;
}
First check if the array length is an even number
if (array.length % 2 === 1) {
return false;
}
Slice the array in half and reverse the 2nd half
let half = (array.length / 2);
let sub1 = array.slice(0, half);
let sub2 = array.slice(-half).reverse();
Then filter both and return matches
return sub1.filter((num, idx) => num === sub2[idx]);
const array1 = [1, 100, 50, -51, 1, 1];
const array2 = [5, 62, 8, 0, 0, 15, 62, -5];
const array3 = [0, 1, 0];
const mirroredValues = array => {
let half;
if (array.length % 2 === 1) {
return false;
} else {
half = (array.length / 2);
}
let sub1 = array.slice(0, half);
let sub2 = array.slice(-half).reverse();
return sub1.filter((num, idx) => num === sub2[idx]);
};
console.log(mirroredValues(array1));
console.log(mirroredValues(array2));
console.log(mirroredValues(array3));
I would do it like this:
const findElementIndex = (array, index = 0) => {
let arr_part_1 = array.slice(0, index).reduce(((a, b) => a + b), 0);
let arr_part_2 = array.slice(index + 1, array.length).reduce(((a, b) => a + b), 0);
return arr_part_1 === arr_part_2 ? index : index === array.length ? -1 : findElementIndex(array, index + 1);
};
console.log('Example 1: ', findElementIndex([1, 1, 10, 2]));
console.log('Example 2: ', findElementIndex([1, 1, 1, 10, 2]));
console.log('Example 3: ', findElementIndex([100, 1, 100]));
That one could be better from performance point of view (reduce only once)
function inTheMiddle(arr) {
let rightSum = arr.slice(2).reduce((total, item) => total + item, 0);
let leftSum = arr[0];
console.log(leftSum, rightSum);
for (let i = 2; i < arr.length; i++) {
if (leftSum === rightSum) {
return i-1;
}
leftSum += arr[i-1];
rightSum -= arr[i];
console.log(leftSum, rightSum);
}
return -1;
}
console.log("In the middle:", inTheMiddle([1,100,50,-51,1,1]))

Regarding quick selection function

first of all thank you for help!
My issue is I'm trying to find kth largest but some of testcases are failing. If argument is [1,1,1] and k = 1. It will hit base case which is undefined. I'm not sure why it's hitting base case. Again, thank you so much! let me know if you guys need more info!
function kth_largest_in_an_array(numbers, k) {
return quickSort3(numbers, k, 0, numbers.length-1);
}
const quickSort3 = (numbers, k, start, end) => {
if (start >= end) {
console.log('base case')
return;
}
//remember random index
console.log('before: ', numbers)
let randomIdx = Math.floor(start + Math.random() * (end - start));
let partitionedIdx = partition(numbers, start, end, randomIdx);
console.log('randomIdx: ',randomIdx)
console.log('partitionedIdx: ',partitionedIdx)
console.log('start: ', start, 'end: ', end)
console.log(numbers.slice(start, end+1))
console.log(numbers)
console.log('number.length: ',numbers.length)
//numbers.length = 5, 5-2 == 3
// console.log('numbers.length - k: ', numbers.length - k)
if (numbers.length - k === partitionedIdx) {
console.log('imin: ', numbers[partitionedIdx])
return numbers[partitionedIdx];
}
else if (partitionedIdx < numbers.length - k) {
return quickSort3(numbers, k, partitionedIdx+1, end);
}
else {
return quickSort3(numbers, k, start, partitionedIdx-1)
}
}
const partition = (numbers, start, end, randomIdx) => {
[numbers[start], numbers[randomIdx]] = [numbers[randomIdx], numbers[start]];
let pivot = numbers[start];
let i = start;
for (let j = i+1; j<=end; j++) {
if (pivot > numbers[j]) {
i++
[numbers[i], numbers[j]] = [numbers[j], numbers[i]];
}
}
[numbers[start], numbers[i]] = [numbers[i], numbers[start]];
return i;
}
console.log(kth_largest_in_an_array([1,1,1], 1))
// console.log(kth_largest_in_an_array([4, 1, 2, 2, 3, 4], 2))
// console.log(kth_largest_in_an_array([5, 1, 10, 3, 2], 2))
Are you looking for something like this?
const t = (arr, kth) => {
const a = arr.sort((a, b) => b - a);
return a[kth];
}
console.log(t([1,1,1], 1))
console.log(t([4, 1, 2, 2, 3, 4], 2))
console.log(t([5, 1, 10, 3, 2], 2))

Given an array of integers, find the second largest and second smallest within the array

I am trying to come up with a function that will take an array of integers and output the 2nd highest number and the 2nd smallest number. The function will take into account floats, duplicates, and negative numbers.
Two functions pass all the tests below except for test2.
var test1 = [7, 7, 12, 98, 106]
answer1 = {2nd Min: 12, 2nd Max: 98}
var test2 = [5, 23, -112, 6, 70, 70, -112]
answer2 = {2nd Min: 5, 2nd Max: 23}
var test3 = [-22, 22]
answer3 = {2nd Min: 22, 2nd Max: -22}
var test4 = [10, 89, 3]
answer = {2nd Min: 10, 2nd Max: 10}
var test5 = [10.4, -12.09, .75, 22]
answer3 = {2nd Min: 0.75, 2nd Max: 10.4}
/*/ \ \
---SOLUTION 1---
\ \ /*/
function secondGreatLow1(arr) {
//make copy of array because it will be spliced in the following functions
var arrCopy = arr.slice();
//push returned values of each function into this the answer array
var answer = []
answer.push(secondMin(arrCopy));
answer.push(secondMax(arrCopy));
return answer;
};
//helper function 1
var secondMin = function (arr){
var arrCopy = arr.slice();
//check length of array
if (arr.length == 2) {
return arr[1];
} else {
var min = Math.min.apply(null, arrCopy);
arrCopy.splice(arrCopy.indexOf(min), 1);
//check for duplicates
for (var i = 0; i < arrCopy.length; i++) {
if (arrCopy.indexOf(min) === -1) {
//.apply is used for arrays
return Math.min.apply(null, arrCopy);
} else {
arrCopy.splice(arrCopy.indexOf(min), 1);
return Math.min.apply(null, arrCopy);
}
};
}
};
//helper function 2
var secondMax = function (arr){
var arrCopy = arr.slice();
if (arr.length == 2) {
return arr[0];
} else {
var max = Math.max.apply(null, arrCopy);
arrCopy.splice(arrCopy.indexOf(max), 1);
//check for duplicates
for (var i = 0; i < arrCopy.length; i++) {
if (arrCopy.indexOf(max) === -1) {
return Math.max.apply(null, arrCopy);
} else {
arrCopy.splice(arrCopy.indexOf(max), 1);
return Math.min.apply(null, arrCopy);
}
};
}
};
/*/ \ \
---SOLUTION 2---
\ \ /*/
function secondGreatLow2 (numbers) {
var arr = withoutDuplicates(numbers);
arr.sort(function(a,b) { return a-b; });
return arr[1] + ' ' + arr[arr.length-2];
};
// helpers
var withoutDuplicates = function(arr) {
var out = [];
for(var i=0; i<arr.length; i++) {
if(i === 0 || arr[i] !== arr[i-1]) {
out.push(arr[i]);
}
}
return out;
};
In your second solution, your withoutDuplicates function appears to operate on the assumption that the list is sorted (checking for duplicates by comparing an element to the previous element); however, in secondGreatLow2, you call withoutDuplicates without performing some sort of sorting.
If you changed the order of those two lines, solution #2 looks valid assuming you don't have any floating point mismatches, ie 3.9999999999997 != 3.99999999998
Not performance efficient for large arrays, but concise:
var a = [5, 23, -112, 6, 70, 70, -112], b = [];
// remove duplicates
b = a.filter(function (item, pos) {
return a.indexOf(item) == pos;
});
// sort
b.sort(function (a, b) {
return a > b;
});
console.log(b[1]); // 2nd min:12
console.log(b[b.length-2]); // 2nd max:12
function get_seconds(a) {
var b = uniq(a); // remove duplicates and sort
var l = b.length;
return [b[1], b[l-2]];
}
Check full tests below:
var tests = {
"case1": {
"input": [7, 7, 12, 98, 106],
"output": [12, 98]
},
"case2": {
"input": [5, 23, -112, 6, 70, 70, -112],
"output": [5, 23]
},
"case3": {
"input": [-22, 22],
"output": [22, -22]
},
"case4": {
"input": [10, 89, 3],
"output": [10, 10]
},
"case5": {
"input": [10.4, -12.09, .75, 22],
"output": [0.75, 10.4]
}
};
function do_tests() {
var res, logs = '',
j_exp, j_res;
$.each(tests, function(c, io) {
j_exp = JSON.stringify(io.output);
res = get_seconds(io.input);
j_res = JSON.stringify(res);
if (j_res == j_exp) {
logs += '<div class="success">' + c + ' passed.</div>';
} else {
logs += '<div class="failed">' + c + ' failed. Expected: ' + j_exp + ', Got: ' + j_res + '</div>';
}
});
$("#log").html(logs);
}
function get_seconds(a) {
var b = uniq(a);
console.log(b, a);
var l = b.length;
return [b[1], b[l - 2]];
}
function uniq(a) {
return a.sort(sortNumber).filter(function(item, pos, ary) {
return !pos || item != ary[pos - 1];
})
}
function sortNumber(a, b) {
return a - b;
}
div#log {
font-family: monospace;
}
div#log > div {
padding: 4px;
margin: 2px;
}
.success {
color: green;
}
.failed {
color: red;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button onclick="do_tests();">Run tests</button>
<div id="log"></div>
This would also work and it appears do be faster (no sorting). What do you guys think?
var secondMax = function(arr){
return Math.min(...arr.reduce((acc, val) =>
(val > Math.min(...acc)) ? [Math.max(...acc), val] : acc
, [-Infinity, -Infinity]))
}
var secondMin = function(arr){
return Math.max(...arr.reduce((acc, val) =>
(val < Math.max(...acc)) ? [Math.min(...acc), val] : acc
, [Infinity, Infinity]))
}
var unique = function(arr) {
return arr.filter((value, index, arr) =>
arr.indexOf(value) === index
)
}
var arr = [7, 7, 12, 98, 106, 106];
console.log(secondMin(unique(arr)));// => 12
console.log(secondMax(unique(arr)));// => 98
console.log(secondMin(arr));// => 7
console.log(secondMax(arr));// => 106
Glad you have found the solution.I am posting this for those who are searching for a simpler solution.This would run on O(n) time.
var fl = arr[0],sl = arr[0];
var fs = Infinity,ss = Infinity;
//find the largest and smallest.
for(var i = 0;i < arr.length;i ++) {
if(arr[i] > fl) fl = arr[i];
if(arr[i] < fs) fs = arr[i];
}
//let us assume smallest is second largest and vice versa.
sl = fs;
ss = fl;
//find second smallest and largest.
for(var i = 0;i < arr.length;i ++) {
if(arr[i] < fl && arr[i] > sl) sl = arr[i];
if(arr[i] > fs && arr[i] < ss) ss = arr[i];
}
console.log("first and second largest : ",fl,sl);
console.log("first and second smallest : ",fs,ss);
This is an easy and simple method for a second highest number but the problem is we could not get a number if there have duplicate exists in the array.
function getSecondLargest(nums) {
if(nums.length<2){
return nums;
}
var first=0;
var second=0;
for(var i=0; i<nums.length;i++)
{
if(nums[i]>first)
{
second = first;
first = nums[i]
}
else(nums[i]>second && nums[i]!=first)
{
second = nums[i];
}
}
return second;
}
If array contains duplicates like nums = [2, 3, 6, 6, 5], the below solution works,
let sortedArray = new Set(nums.sort((a, b) => b - a ));
console.log('second smallest', [...sortedArray][sortedArray.size - 2])
console.log('second largest',[...sortedArray][1]);
C program for arrays to find second largest and second smallest in a array.
#include<stdio.h>
void main()
{
int arr[20];
int small,big,big2,small2;
int i,num;
printf("Enter Number of elements:");
scanf("%d",&num);
printf("Enter the elements: \n");
for(i=0;i<num;i++)
scanf("%d",&arr[i]);//Entering elements
big = arr[0];//For big in array
small = arr[0];// For small in array
for(i=0;i<num;i++)
{
if(arr[i]>big)
{
big2 = big;
big = arr[i];
}
if(arr[i]<small)
{
small2 = small;
small = arr[i];
}
}
printf("The biggest is %d\n",big);
printf("The smallest is %d\n",small);
printf("The second biggest is %d\n",big2);
printf("The second smallest is %d\n",small2);
}
#tej
let ar = [1,4,76,80,90,3,6,82];
var big = 0,sbig=0;
for(let i=0; i<ar.length;i++){
if(big < ar[i]) {
sbig = big;
big = ar[i]
continue;
}
if(sbig < ar[i]) {
sbig = ar[i];
}
}
console.log(sbig,big);

JavaScript quicksort

I have been looking around the web for a while and I am wondering if there is a 'stable' defacto implementation of quicksort that is generally used? I can write my own but why reinvent the wheel...
Quicksort (recursive)
function quicksort(array) {
if (array.length <= 1) {
return array;
}
var pivot = array[0];
var left = [];
var right = [];
for (var i = 1; i < array.length; i++) {
array[i] < pivot ? left.push(array[i]) : right.push(array[i]);
}
return quicksort(left).concat(pivot, quicksort(right));
};
var unsorted = [23, 45, 16, 37, 3, 99, 22];
var sorted = quicksort(unsorted);
console.log('Sorted array', sorted);
You can easily "stabilize" an unstable sort using a decorate-sort-undecorate pattern
function stableSort(v, f)
{
if (f === undefined) {
f = function(a, b) {
a = ""+a; b = ""+b;
return a < b ? -1 : (a > b ? 1 : 0);
}
}
var dv = [];
for (var i=0; i<v.length; i++) {
dv[i] = [v[i], i];
}
dv.sort(function(a, b){
return f(a[0], b[0]) || (a[1] - b[1]);
});
for (var i=0; i<v.length; i++) {
v[i] = dv[i][0];
}
}
the idea is to add the index as last sorting term so that no two elements are now "the same" and if everything else is the same the original index will be the discriminating factor.
Put your objects into an array.
Call Array.sort(). It's very fast.
var array = [3,7,2,8,2,782,7,29,1,3,0,34];
array.sort();
console.log(array); // prints [0, 1, 2, 2, 29, 3, 3, 34, 7, 7, 782, 8]
Why does that print in lexicographic order? That's how array.sort() works by default, e.g. if you don't provide a comparator function. Let's fix this.
var array = [3,7,2,8,2,782,7,29,1,3,0,34];
array.sort(function (a, b)
{
return a-b;
});
console.log(array); // prints [0, 1, 2, 2, 3, 3, 7, 7, 8, 29, 34, 782]
Quick Sort (ES6)
function quickSort(arr) {
if (arr.length < 2) {
return arr;
}
const pivot = arr[Math.floor(Math.random() * arr.length)];
let left = [];
let right = [];
let equal = [];
for (let val of arr) {
if (val < pivot) {
left.push(val);
} else if (val > pivot) {
right.push(val);
} else {
equal.push(val);
}
}
return [
...quickSort(left),
...equal,
...quickSort(right)
];
}
Few notes:
A random pivot keeps the algorithm efficient even when the data is sorted.
As much as it nice to use Array.filter instead of using for of loop, like some of the answers here, it will increase time complexity (Array.reduce can be used instead though).
A Functional equivalent
In celebration of Functional Javascript, which appears to be the in thing
at the moment, especially given ES6+ wonderful syntactic sugar additions. Arrow functions and destructuring I propose a very clean, short functional equivalent of the quicksort function. I have not tested it for performance or compared it to the built-in quicksort function but it might help those who are struggling to understand the practical use of a quicksort. Given its declarative nature it is very easy to see what is happening as oppose to how it works.
Here is a JSBin version without comments https://jsbin.com/zenajud/edit?js,console
function quickSortF(arr) {
// Base case
if (!arr.length) return []
// This is a ES6 addition, it uses destructuring to pull out the
// first value and the rest, similar to how other functional languages
// such as Haskell, Scala do it. You can then use the variables as
// normal below
const [head, ...tail] = arr,
// here we are using the arrow functions, and taking full
// advantage of the concise syntax, the verbose version of
// function(e) => { return e < head } is the same thing
// so we end up with the partition part, two arrays,
// one smaller than the pivot and one bigger than the
// pivot, in this case is the head variable
left = tail.filter( e => e < head),
right = tail.filter( e => e >= head)
// this is the conquer bit of divide-and-conquer
// recursively run through each left and right array
// until we hit the if condition which returns an empty
// array. These results are all connected using concat,
// and we get our sorted array.
return quickSortF(left).concat(head, quickSortF(right))
}
const q7 = quickSortF([11,8,14,3,6,2,7])
//[2, 3, 6, 7, 8, 11, 14]
const q8 = quickSortF([11,8,14,3,6,2,1, 7])
//[1, 2, 3, 6, 7, 8, 11, 14]
const q9 = quickSortF([16,11,9,7,6,5,3, 2])
//[2, 3, 5, 6, 7, 9, 11, 16]
console.log(q7,q8,q9)
The comments should provide enough if it is already not clear what is happening. The actual code is very short without comments, and you may have noticed I am not a fan of the semicolon. :)
In this blog http://www.nczonline.net/blog/2012/11/27/computer-science-in-javascript-quicksort/ which has pointed out that
Array.sort is implemented in quicksort or merge sort internaly.
Quicksort is generally considered to be efficient and fast and so is
used by V8 as the implementation for Array.prototype.sort() on arrays
with more than 23 items. For less than 23 items, V8 uses insertion
sort[2]. Merge sort is a competitor of quicksort as it is also
efficient and fast but has the added benefit of being stable. This is
why Mozilla and Safari use it for their implementation of
Array.prototype.sort().
and when using Array.sort,you should return -1 0 1 instead of true or false in Chrome.
arr.sort(function(a,b){
return a<b;
});
// maybe--> [21, 0, 3, 11, 4, 5, 6, 7, 8, 9, 10, 1, 2, 12, 13, 14, 15, 16, 17, 18, 19, 20, 22]
arr.sort(function(a,b){
return a > b ? -1 : a < b ? 1 : 0;
});
// --> [22, 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0]
var array = [8, 2, 5, 7, 4, 3, 12, 6, 19, 11, 10, 13, 9];
quickSort(array, 0, array.length -1);
document.write(array);
function quickSort(arr, left, right)
{
var i = left;
var j = right;
var tmp;
pivotidx = (left + right) / 2;
var pivot = parseInt(arr[pivotidx.toFixed()]);
/* partition */
while (i <= j)
{
while (parseInt(arr[i]) < pivot)
i++;
while (parseInt(arr[j]) > pivot)
j--;
if (i <= j)
{
tmp = arr[i];
arr[i] = arr[j];
arr[j] = tmp;
i++;
j--;
}
}
/* recursion */
if (left < j)
quickSort(arr, left, j);
if (i < right)
quickSort(arr, i, right);
return arr;
}
Using ES6 rest, spread:
smaller = (a, list) => list.filter(x => x <= a)
larger = (a, list) => list.filter(x => x > a)
qsort = ([x, ...list]) => (!isNaN(x))
? [...qsort(smaller(x, list)), x, ...qsort(larger(x, list))]
: []
This algorithm work almost as fast as the default implementation
of Array.prototype.sort in chrome.
function quickSort(t){
_quickSort(t,0,t.length-1,0,t.length-1);
}
function _quickSort(t, s, e, sp, ep){
if( s>=e ) return;
while( sp<ep && t[sp]<t[e] ) sp++;
if( sp==e )
_quickSort(t,s,e-1,s,e-1);
else{
while(t[ep]>=t[e] && sp<ep ) ep--;
if( sp==ep ){
var temp = t[sp];
t[sp] = t[e];
t[e] = temp;
if( s!=sp ){
_quickSort(t,s,sp-1,s,sp-1);
}
_quickSort(t,sp+1,e,sp+1,e);
}else{
var temp = t[sp];
t[sp] = t[ep];
t[ep] = temp;
_quickSort(t,s,e,sp+1,ep);
}
}
}
quickSort time (ms): 738
javaScriptSort time (ms): 603
var m = randTxT(5000,500,-1000,1000);
VS(m);
function VS(M){
var t;
t = Date.now();
for(var i=0;i<M.length;i++){
quickSort(M[i].slice());
}console.log("quickSort time (ms): "+(Date.now()-t));
t = Date.now();
for(var i=0;i<M.length;i++){
M[i].slice().sort(compare);
}console.log("javaScriptSort time (ms): "+(Date.now()-t));
}
function compare(a, b) {
if( a<b )
return -1;
if( a==b )
return 0;
return 1;
}
function randT(n,min,max){
var res = [], i=0;
while( i<n ){
res.push( Math.floor(Math.random()*(max-min+1)+min) );
i++;
}
return res;
}
function randTxT(n,m,min,max){
var res = [], i=0;
while( i<n ){
res.push( randT(m,min,max) );
i++;
}
return res;
}
Yet another quick sort demonstration, which takes middle of the array as pivot for no specific reason.
const QuickSort = function (A, start, end) {
//
if (start >= end) {
return;
}
// return index of the pivot
var pIndex = Partition(A, start, end);
// partition left side
QuickSort(A, start, pIndex - 1);
// partition right side
QuickSort(A, pIndex + 1, end);
}
const Partition = function (A, start, end) {
if (A.length > 1 == false) {
return 0;
}
let pivotIndex = Math.ceil((start + end) / 2);
let pivotValue = A[pivotIndex];
for (var i = 0; i < A.length; i++) {
var leftValue = A[i];
//
if (i < pivotIndex) {
if (leftValue > pivotValue) {
A[pivotIndex] = leftValue;
A[i] = pivotValue;
pivotIndex = i;
}
}
else if (i > pivotIndex) {
if (leftValue < pivotValue) {
A[pivotIndex] = leftValue;
A[i] = pivotValue;
pivotIndex = i;
}
}
}
return pivotIndex;
}
const QuickSortTest = function () {
const arrTest = [3, 5, 6, 22, 7, 1, 8, 9];
QuickSort(arrTest, 0, arrTest.length - 1);
console.log("arrTest", arrTest);
}
//
QuickSortTest();
I really thought about this question. So first I found the normal search mode and wrote.
let QuickSort = (arr, low, high) => {
if (low < high) {
p = Partition(arr, low, high);
QuickSort(arr, low, p - 1);
QuickSort(arr, p + 1, high);
}
return arr.A;
}
let Partition = (arr, low, high) => {
let pivot = arr.A[high];
let i = low;
for (let j = low; j <= high; j++) {
if (arr.A[j] < pivot) {
[arr.A[i], arr.A[j]] = [arr.A[j], arr.A[i]];
i++;
}
}
[arr.A[i], arr.A[high]] = [arr.A[high], arr.A[i]];
return i;
}
let arr = { A/* POINTER */: [33, 22, 88, 23, 45, 0, 44, 11] };
let res = QuickSort(arr, 0, arr.A.length - 1);
console.log(res);
Result is [0, 11, 22, 23, 33, 44, 45, 88]
But its not stable; so I checked the other answers and the Idea of #6502 was interesting to me that "two items do not have to be the same" to be distinguishable.
Well, I have a solution in my mind, but it is not optimal. We can keep the indexes of the items in a separate array. Memory consumption will almost double in this idea.
arr.A => Array of numbers
arr.I => Indexes related to each item of A
influencer => This should be a very very small number; I want to use this as a factor to be able to distinguish between similar items.
So we can change the partition like this:
let Partition = (arr, low, high) => {
let pivot = arr.A[high];
let index = arr.I[high];
let i = low;
for (let j = low; j <= high; j++) {
if (arr.A[j] + (arr.I[j] * influencer) < pivot + (index * influencer)) {
[arr.A[i], arr.A[j]] = [arr.A[j], arr.A[i]];
[arr.I[i], arr.I[j]] = [arr.I[j], arr.I[i]];
i++;
}
}
[arr.A[i], arr.A[high]] = [arr.A[high], arr.A[i]];
[arr.I[i], arr.I[high]] = [arr.I[high], arr.I[i]];
return i;
}
let influencer = 0.0000001;
let arr = {
I/* INDEXES */: [10, 11, 12, 13, 14, 15, 16, 17, 18, 19],
A/* POINTER */: [33, 22, 88, 33, 23, 45, 33, 89, 44, 11]
};
let res = QuickSort(arr, 0, arr.A.length - 1);
console.log(res);
Result:
I: [19, 11, 14, 10, 13, 16, 18, 15, 12, 17],
A: [11, 22, 23, 33, 33, 33, 44, 45, 88, 89]
More compact and easy to understand quicksort implementation
const quicksort = arr =>
arr.length <= 1
? arr
: [
...quicksort(arr.slice(1).filter((el) => el < arr[0])),
arr[0],
...quicksort(arr.slice(1).filter((el) => el >= arr[0])),
];
try my solution
const quickSort = (arr) => {
// base case
if(arr.length < 2) return arr;
// recurisve case
// pick a random pivot
let pivotIndex = Math.floor(Math.random() * arr.length);
let pivot = arr[pivotIndex];
let left = [];
let right = [];
// make array of the elements less than pivot and greater than it
for(let i = 0; i < arr.length; i++) {
if(i === pivotIndex) {
continue;
}
if(arr[i] < pivot) {
left.push(arr[i])
} else {
right.push(arr[i])
}
}
// call the recursive case again
return quickSort(left).concat([pivot], quickSort(right));
}
when testing this
quickSort([7, 5, 3, 2, 8, 1, 5]) // returns [[1, 2, 3, 5, 5, 7, 8]]
This is it !!!
function typeCheck(a, b){
if(typeof a === typeof b){
return true;
}else{
return false;
}
}
function qSort(arr){
if(arr.length === 0){
return [];
}
var leftArr = [];
var rightArr = [];
var pivot = arr[0];
for(var i = 1; i < arr.length; i++){
if(typeCheck(arr[i], parseInt(0))){
if(arr[i] < pivot){
leftArr.push(arr[i]);
}else { rightArr.push(arr[i]) }
}else{
throw new Error("All must be integers");
}
}
return qSort(leftArr).concat(pivot, qSort(rightArr));
}
var test = [];
for(var i = 0; i < 10; i++){
test[i] = Math.floor(Math.random() * 100 + 2);
}
console.log(test);
console.log(qSort(test));
Slim version:
function swap(arr,a,b){
let temp = arr[a]
arr[a] = arr[b]
arr[b] = temp
return 1
}
function qS(arr, first, last){
if(first > last) return
let p = first
for(let i = p; i < last; i++)
if(arr[i] < arr[last])
p += swap(arr, i, p)
swap(arr, p, last)
qS(arr, first, p - 1)
qS(arr, p + 1, last)
}
Tested with random values Arrays, and seems to be always faster than Array.sort()
quickSort = (array, left, right) => {
if (left >= right) {
return;
}
const pivot = array[Math.trunc((left + right) / 2)];
const index = partition(array, left, right, pivot);
quickSort(array, left, index - 1);
quickSort(array, index, right);
}
partition = (array, left, right, pivot) => {
while (left <= right) {
while (array[left] < pivot) {
left++;
}
while (array[right] > pivot) {
right--;
}
if (left <= right) {
swap(array, left, right);
left++;
right--;
}
}
return left;
}
swap = (array, left, right) => {
let temp = array[left];
array[left] = array[right];
array[right] = temp;
}
let array = [1, 5, 2, 3, 5, 766, 64, 7678, 21, 567];
quickSort(array, 0, array.length - 1);
console.log('final Array: ', array);
A Fastest implementation
const quickSort = array =>
(function qsort(arr, start, end) {
if (start >= end) return arr;
let swapPos = start;
for (let i = start; i <= end; i++) {
if (arr[i] <= arr[end]) {
[arr[swapPos], arr[i]] = [arr[i], arr[swapPos]];
swapPos++;
}
}
qsort(arr, start, --swapPos - 1);
qsort(arr, swapPos + 1, end);
return arr;
})(Array.from(array), 0, array.length - 1);
Quicksort using ES6, filter and spread operation.
We establish a base case that 0 or 1 elements in an array are already sorted. Then we establish an inductive case that if quicksort works for 0 or 1 elements, it can work for an array of size 2. We then divide and conquer until and recursively call our function until we reach our base case in the call stack to get our desired result.
O(n log n)
const quick_sort = array => {
if (array.length < 2) return array; // base case: arrays with 0 or 1 elements are already "sorted"
const pivot = array[0]; // recursive case;
const slicedArr = array.slice(1);
const left = slicedArr.filter(val => val <= pivot); // sub array of all elements less than pivot
const right = slicedArr.filter(val => val > pivot); // sub array of all elements greater than pivot
return [...quick_sort(left), pivot, ...quick_sort(right)];
}
const quicksort = (arr)=>{
const length = Math.ceil(arr.length/2);
const pivot = arr[length];
let newcondition=false;
for(i=0;i<length;i++){
if(arr[i]>arr[i+1]){
[arr[i], arr[i+1]] = [arr[i+1], arr[i]]
newcondition =true
}
}
for(i=arr.length;i>length-1;i--){
if(arr[i]>arr[i+1]){
[arr[i], arr[i+1]] = [arr[i+1], arr[i]]
newcondition =true
}
}
return newcondition? quicksort(arr) :arr
}
const t1 = performance.now();
const t2 = performance.now();
console.log(t2-t1);
console.log(quicksort([3, 2, 4, 9, 1, 0, 8, 7]));
const quicksort = (arr)=>{
if (arr.length < 2) return arr;
const pivot = arr[0];
const left = [];
const right = [];
arr.shift();
arr.forEach(number => {
(number<pivot) ? left.push(number) : right.push(number);
});
return ([...quicksort(left), pivot, ...quicksort(right)]);
}
console.log(quicksort([6, 23, 29, 4, 12, 3, 0, 97]));
How about this non-mutating functional QuickSort:
const quicksort = (arr, comp, iArr = arr) => {
if (arr.length < 2) {
return arr;
}
const isInitial = arr.length === iArr.length;
const arrIndexes = isInitial ? Object.keys(arr) : arr;
const compF = typeof comp === 'function'
? comp : (left, right) => left < right ? -1 : right < left ? 1 : 0;
const [pivotIndex, ...indexesSansPivot] = arrIndexes;
const indexSortReducer = isLeftOfPivot => [
(acc, index) => isLeftOfPivot === (compF(iArr[index], iArr[pivotIndex]) === -1)
? acc.concat(index) : acc,
[]
];
const ret = quicksort(indexesSansPivot.reduce(...indexSortReducer(true)), compF, iArr)
.concat(pivotIndex)
.concat(quicksort(indexesSansPivot.reduce(...indexSortReducer(false)), compF, iArr));
return isInitial ? ret.reduce((acc, index) => acc.concat([arr[index]]), []) : ret;
};
As a bonus, it supports optional comparing function which enables sorting of array of objects per property/properties, and doesn't get slower if dealing with larger values/objects.
First quick sorts original array keys, then returns sorted copy of original array.

Categories

Resources