Sort array using the positions - javascript

I've got an array as below.
var FruitArr = [5, "Mango", 3, "Apple", 2, "Lychee", 1, "Banana", 4, "Pineapple"];
How can I sort the fruit names according to the number before it and add to an empty array? The array has been stored as position , item.
The expected output is
var newFruitArr = ["Banana", "Lychee", "Apple", "Pineapple", "Mango"];
EDIT:
The reason for having items as it is shown: In my actual code the fruit names are base64 url string which is created on the fly. The base64 creating depends based on the image. Therefore I couldn't think of a better way of adding the url strings in to the array. So I added items to the array as 'desired position', 'base64 string'. I thought of sorting them once all conversions are done. I did use .splice() which did not work as expected because of the above reason.

There is no need to sort, you already have the indexes in your input array.
Just preallocate your new array and fill it.
var fruits = [2, "apple", 1, "orange"],
fruitsLength = fruits.length;
var newFruitArr = new Array(fruitsLength / 2);
for (var i = 0; i < fruitsLength; i += 2)
newFruitArr[fruits[i] - 1] = fruits[i + 1];

Does this fit your need ?
function sort (arr) {
var min, minId = -1, output = [];
while (arr.length >= 2) {
for (var i = 0; i < arr.length; i += 2) {
if (arr[i] < min || minId == -1) {
minId = i;
min = arr[i];
}
}
output.push(arr[minId + 1]);
arr.splice(minId, 2);
minId = -1;
}
return output;
}
It search for the minimum number, push the corresponding fruit to the output and remove the couple from the input array, until there's nothing in it. Quite simple, surely not the most effective solution.

You have to convert your array to a form easy to use with sort method.
Here is the code to do so:
var result = [];
FruitArr.forEach(function (el, i) {
if (i % 2) result.push({value: el, weight: FruitArr[i-1]});
});
The result array will be:
[{value: "Mango", weight: 5}, {value: "Apple", weight: 3}, {value: "Lychee", weight: 2}, {value: "Bananna", weight: 1}, {value: "Pineapple", weight: 4}];
which easy to sort with sort method.

I actually prefer insertion-sort-algo to sort an array because of performance issues:
var arr = [5, "Mango", 3, "Apple", 2, "Lychee", 1, "Bananna", 4, "Pineapple"];
var groups = [];
for(var f=0; f < arr.length; f+=2)groups.push([arr[f],arr[f+1]]);
function insertion_sort(array){
for(var o=1; o < array.length;o++){
for(var i=o; i>0 && array[i][0] < array[i-1][0];i--){
var tmp = array[i];
array[i] = array[i-1];
array[i-1] = tmp;
}
}
return array;
}
insertion_sort(groups); // [[1, "Bananna"], [2, "Lychee"], [3, "Apple"], [4, "Pineapple"], [5, "Mango"]]

Related

Javascript: Split an array according to a pattern: items 1, 5, 10, then 2, 6, 11, then 3, 7, 12

I am trying to split an array which has a repeating pattern of elements 1, 2, 3, and 4. I want to turn my array [1,2,3,4,5,6,7,8,9,10] into four arrays: [1,5,10], [2,6,11], [3,7,12], and [4,8,13]. I tried using multiples, but the result creates the new arrays in a wrong order. Here is my attempt:
var upload_names_and_ids = [
"Certificat de salaire", //first line is the upload's visible title
"certificat-de-salaire", //second line is the upload's id
"no-info-circle", //third line is the info-circle class
"", //fourth line is the info-circle text
"Allocations Familiales",
"alloc-familiales",
"no-info-circle",
"",
"Courrier Impot (déclaration précédente)",
"courrier-impot",
"info-circle right",
""
];
//Seperate our first array into 4
var upload_names = [];
var upload_ids = [];
var upload_info_circle_class = [];
var upload_info_circle_content = [];
for (var i=0; i<upload_names_and_ids.length; i++){
if (i%4==0) {
upload_info_circle_content.push(upload_names_and_ids[i]);
} else if (i%3==0) {
upload_info_circle_class.push(upload_names_and_ids[i]);
} else if (i%2==0) {
upload_names.push(upload_names_and_ids[i]);
} else {
upload_ids.push(upload_names_and_ids[i]);
}
}
Any help is much appreciated, thank you!
You could take a remainder with index and wanted length.
const
array = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16],
length = 4,
result = array.reduce(
(r, v, i) => (r[i % length].push(v), r),
Array.from({ length }, _ => [])
);
console.log(result);
If you like to use predeclared array directly, you could replace this line
Array.from({ length }, _ => [])
with
[upload_names, upload_ids, upload_info_circle_class, upload_info_circle_content]
where the accumulator of Array#reduce keeps the object references.
It's not i%3==0 (which matches 0, 3, 6, …) but i%4==1 (to match 1, 5, 10, …). Same for i%2==0.
I would add a helper sliceN that takes an array and a positive integer. Then returns an array of arrays where the inner arrays are of length n.
sliceN([1,2,3,4,5,6,7,8,9], 3) //=> [[1,2,3], [4,5,6], [7,8,9]]
sliceN([1,2,3,4,5,6], 2) //=> [[1,2], [3,4], [5,6]]
Then also add a helper transpose that transposes a matrix.
transpose([[1,2,3], [4,5,6], [7,8,9]]) //=> [[1,4,7], [2,5,8], [3,6,9]]
transpose([[1,2], [3,4], [5,6]]) //=> [[1,3,5], [2,4,6]]
With these two helpers you can create the wanted result with ease.
const upload_names_and_ids = [
"Certificat de salaire", //first line is the upload's visible title
"certificat-de-salaire", //second line is the upload's id
"no-info-circle", //third line is the info-circle class
"", //fourth line is the info-circle text
"Allocations Familiales",
"alloc-familiales",
"no-info-circle",
"",
"Courrier Impot (déclaration précédente)",
"courrier-impot",
"info-circle right",
""
];
const [
upload_names,
upload_ids,
upload_info_circle_class,
upload_info_circle_content,
] = transpose(sliceN(upload_names_and_ids, 4));
console.log(upload_names);
console.log(upload_ids);
console.log(upload_info_circle_class);
console.log(upload_info_circle_content);
function sliceN(array, n) {
const slices = [];
for (let i = 0; i < array.length; i += n) {
slices.push(array.slice(i, i + n));
}
return slices;
}
function transpose(rows) {
if (rows.length == 0) return [];
const columns = rows[0].map(cell => Array.of(cell));
for (let iRow = 1; iRow < rows.length; iRow += 1) {
for (let iCol = 0; iCol < columns.length; iCol += 1) {
columns[iCol].push(rows[iRow][iCol]);
}
}
return columns;
}
If you are already use a library with helper functions chances are that one or both of these data transforming methods are present. sliceN can often be found as something with split, slice or chunk in the name. transpose is very specific and if present will probably be present under the same name.
As an example Ramda offers both these methods.
R.transpose(R.splitEvery(4, upload_names_and_ids))

Count occurring pairs in array - Javascript

I want to find and count the pair of values within an array.
For example:
var Array = ["Apple", "Pear", "Mango", "Strawberry", "Apple", "Pear", "Orange"];
Now I want to count how many times each pair (Apple and Pear, Pear and Mango and so on...) occurs in the array. If the array has uneven pair, the last value should then be zero.
The output of the array in the example should then be:
[2,1,1,1,1]
Notice that the "Apple, Pear" occurs 2 times so then the count will be two and put in the first number of the new array.
I hope I explained good enough
You could use a hash table for counting pairs by using two adjacent values and build a key of it for counting. Then use the values as result.
var array = ['Apple', 'Pear', 'Mango', 'Strawberry', 'Apple', 'Pear', 'Orange'],
count = {},
result;
array.reduce((a, b) => {
var key = [a, b].join('|');
count[key] = (count[key] || 0) + 1;
return b;
});
result = Object.values(count);
console.log(result);
console.log(count);
You could use sort() taking advantage of the fact that it passes the pairs needed to the callback:
var arr = ["Apple", "Pear", "Mango", "Strawberry", "Apple", "Pear", "Orange"];
var pairs = {}
arr.sort((a,b)=>{
(a+b in pairs)?pairs[a+b]++:pairs[a+b] = 1;
})
console.log(Object.values(pairs))
This is the simplest way to do it. It is similar to the answer given by #Nina Scholz above, but without having to join or anything like that. Also note that, while it defaults to pairs (i.e., 2), it is generic enough to check for triples, quadruples, and so on:
function CountMultiples(inputArray, quantity = 2) {
var count = {};
return inputArray.reduce((acc, val) => {
count[val] = (count[val] || 0) + 1;
return count[val] % quantity > 0 ? acc : ++acc;
}, 0);
};
var a = [1, 1, 2, 3, 4, 5, 6, 7, 8, 9, 9, 0, 0, 0, 6];
console.log(CountMultiples(a,4));//0
console.log(CountMultiples(a,3));//1
console.log(CountMultiples(a));//4

Removing an array of indexes from an given array

So I am having a bit of difficulty trying to think of the best way of doing this in javascript. I want to remove an array of unsorted indexes from an array that was X number of elements. For example
var index = [ 0, 7, 10, 2, 5, 11]
array = [{field0: 0}, {field1: 1}, {field2: 2}, ... {field5: 5}, {field6: 6}...]
So I tried using a nested for loop with splice, but then when I splice, my array loses its indexing and screws up.
The end result should come out to be like
array = [{field1: 1}, {field3: 3}, {field4: 4}, .... {field6: 6} ...]
Any help would be greatly appreciated.
The solution to your problem is really a one-liner:
array = [00,11,22,33,44,55,66,77];
indexes = [1,7,5,3];
array = array.filter(function(_,i) { return indexes.indexOf(i) < 0 });
document.write('<pre>'+JSON.stringify(array,0,3));
If sorting the array of elements to remove is not an issue, you can just do the following:
var array = [{field0: 0}, {field1: 1}, {field2: 2}, {field3: 3}, {field4: 4}, {field5: 5}, {field6: 6}, {field7: 7}, {field8: 8}, {field9: 9}];
var indices = [0, 7, 2, 5];
indices.sort(function(a, b) {
if ( a > b ) {
return 1;
} else if ( b > a ) {
return -1;
} else {
return 0;
}
});
for (var i = 0, offset = 0; i < indices.length; i++, offset++) {
array.splice(indices[i] - offset, 1);
}
console.log(array);
And if for some reason you were unable to sort the array of indices to remove, you could keep track of the offset with the following:
var array = [{field0: 0}, {field1: 1}, {field2: 2}, {field3: 3}, {field4: 4}, {field5: 5}, {field6: 6}, {field7: 7}, {field8: 8}, {field9: 9}];
var indices = [0, 7, 2, 5];
var removedIndices = [];
function calcOffset(val) {
var numRemoved = 0;
for (var j = 0; j < removedIndices.length; j++) {
if (val > removedIndices[j]) {
numRemoved++;
}
}
return numRemoved;
}
for (var i = 0, offset = 0; i < indices.length; i++, offset++) {
var offset = calcOffset(indices[i]);
array.splice(indices[i] - offset, 1);
removedIndices.push(indices[i]);
}
console.log(array);
I would iterate through array (for/next loop) and at each element see if the number exist in index (index.indexOf(n)). If it does, push the element to a new temporary array.
when you are done, either copy the temp array back to array OR array.length = 0 and push the elements from the temp array back onto the original array.
something like this:
var index = [ 0, 7, 10, 2, 5, 11]
var array = [{field0: 0}, {field1: 1}, {field2: 2},{field3: 3}, {field4: 4}];
var tempArray = [];
for(var arrayIndex = 0;arrayIndex < array.length;arrayIndex++){
if(index.indexOf(arrayIndex) === -1)
{
tempArray.push(array[arrayIndex]);
}
}
array = tempArray;
You can try deleting them with delete array[index[count]] by looping as long as undefined is not a problem.
Or, you can set loop through all the elements in the array and set any element whose index is not present to false. Then, loop through them again and copy only the ones which are not false to new array.
newArray = new Array();
for (var i = 0; i < array.length; i++) {
for(var j=0; j<index.length; j++) {
if (index[j] == i) {
array[i] = false;
}
}
};
for (var i = 0; i < array.length; i++) {
if (array[i] != false) {
newArray[i] = array[i];
}
}

Split array into sub arrays and replace character

I need to split an array into several sub arrays and replace a certain character.
First I run a function to count the number of duplicates in the array. Then I build a new array with the values and the number of instances of the value.
Code:
angular.forEach($scope.financial, function(data) {
counts[data] = (counts[data] || 0)+1;
})
Result:
[4, {25: 4}, 5, {25: 1}, 3, {10: 1}, 4, {10: 1}]
What I am looking for is to split the array into several sub arrays and replace the colon with a comma.
Like this:
[[4,25,4],[5,25,1],[3,10,1],[4,10,1]]
Any suggestions?
That can be done with a simple loop. But, some checks for the integrity of the data would be advised if you can't guarantee the format of the input.
function getKey(o) {
for (var prop in o) {
if (o.hasOwnProperty(prop)) {
return prop;
}
}
}
var data = [4, {25: 4}, 5, {25: 1}, 3, {10: 1}, 4, {10: 1}];
var i = 0;
var output = [];
var key;
for (i = 0; i < data.length; i += 2) {
key = getKey(data[i + 1]);
output.push([data[i], parseInt(key, 10), data[i + 1][key]]);
}
//Print the output
console.log(output);
var el = document.createElement('div');
el.innerHTML = JSON.stringify(output);
document.body.appendChild(el);
The below mentioned converter function will accept the reponseArray of type [4, {25: 4}, 5, {25: 1}, 3, {10: 1}, 4, {10: 1}] and converts into subarray [[4,25,4],[5,25,1],[3,10,1],[4,10,1]]
fiddle
function converter(responseArray) {
var mainArray=[], subArray;
for (var i = 0; i < responseArray.length; i++) {
if(i%2 == 0) {
subArray= [];
subArray.push(responseArray[i]);
} else {
var obj = responseArray[i];
for(var key in obj) {
subArray.push(key * 1);
subArray.push(obj[key] * 1);
}
mainArray.push(subArray);
}
}
console.log(mainArray);
return mainArray;
}

Sort Object Containing Multiple Arrays: JavaScript [duplicate]

for hours i've been trying to figure out how to sort 2 array dependently.
Let's say I have 2 arrays.
First one:
array1 = ['zzzzz', 'aaaaaa', 'ccccc'];
and the second one:
array2 = [3, 7, 1];
I sort the first one with array1.sort(); and it becomes [aaaaaa, cccccc, zzzzzz]
now what I want is that the second one becomes [7, 1, 3]
I think it's quite simple but i'm trying to implement this in something a little more complex, im new and i keep mixing up things.
Thanks
I would "zip" them into one array of objects, then sort that with a custom sort callback, then "unzip" them back into the two arrays you wanted:
var array1 = ['zzzzz', 'aaaaaa', 'ccccc'],
array2 = [3, 7, 1],
zipped = [],
i;
for(i=0; i<array1.length; ++i) {
zipped.push({
array1elem: array1[i],
array2elem: array2[i]
});
}
zipped.sort(function(left, right) {
var leftArray1elem = left.array1elem,
rightArray1elem = right.array1elem;
return leftArray1elem === rightArray1elem ? 0 : (leftArray1elem < rightArray1elem ? -1 : 1);
});
array1 = [];
array2 = [];
for(i=0; i<zipped.length; ++i) {
array1.push(zipped[i].array1elem);
array2.push(zipped[i].array2elem);
}
alert('Sorted arrays:\n\narray1: ' + array1 + '\n\narray2: ' + array2);
Here's a working fiddle.
Here's a simple function that will do the trick:
function sortTogether(array1, array2) {
var merged = [];
for(var i=0; i<array1.length; i++) { merged.push({'a1': array1[i], 'a2': array2[i]}); }
merged.sort(function(o1, o2) { return ((o1.a1 < o2.a1) ? -1 : ((o1.a1 == o2.a1) ? 0 : 1)); });
for(var i=0; i<merged.length; i++) { array1[i] = merged[i].a1; array2[i] = merged[i].a2; }
}
Usage demo (fiddle here):
var array1 = ['zzzzz', 'aaaaaa', 'ccccc'];
var array2 = [3, 7, 1];
console.log('Before..: ',array1,array2);
sortTogether(array1, array2); // simply call the function
console.log('After...: ',array1,array2);
Output:
Before..: ["zzzzz", "aaaaaa", "ccccc"] [3, 7, 1]
After...: ["aaaaaa", "ccccc", "zzzzz"] [7, 1, 3]
Instead of two arrays of primitive types (strings, numbers) you can make an array of objects where one property of the object is string (containing "aaaaa", "cccccc", "zzzzzz") and another is number (7,1,3). This way you will have one array only, which you can sort by any property and the other property will remain in sync.
It just so happens I had some old code lying around that might do the trick:
function arrVirtualSortGetIndices(array,fnCompare){
var index=array.map(function(e,i,a){return i;});
fnCompare=fnCompare || defaultStringCompare;
var idxCompare=function (aa,bb){return fnCompare(array[aa],array[bb]);};
index.sort(idxCompare);
return index;
function defaultStringCompare(aa,bb){
if(aa<bb)return -1;
if(bb<aa)return 1;
return 0;
}
function defaultNumericalCompare(aa,bb){
return aa-bb;
}
}
function arrReorderByIndices(array,indices){
return array.map(
function(el,ix,ar){
return ar[indices[ix]];
}
);
}
var array1 = ['zzzzz', 'aaaaaa', 'ccccc'];
var array2 = [3, 7, 1];
var indices=arrVirtualSortGetIndices(array1);
var array2sorted=arrReorderByIndices(array2,indices);
array2sorted;
/*
7,1,3
*/
Sorry, I don't do 'fors'. At least not when I don't have to.
And fiddle.
Also, an alternative fiddle that sorts the results when given an array of objects like this:
given:
var list = [
{str:'zzzzz',value:3},
{str:'aaaaa',value:7},
{str:'ccccc',value:1}
];
outputs:
[
{str: "aaaaa", value: 7},
{str: "ccccc", value: 1},
{str: "zzzzz", value: 3}
]
Assumption:
The arrays are the same length (this is implied by your question)
the contents can be compared with > and < (true in your example, but I wanted to make it clear that it was assumed here)
So then we can use an insertion sort.
var value,len = array1.length;
for (i=0; i < len; i++) {
value = array1[i];
for (j=i-1; j > -1 && array1[j] > value; j--) {
array1[j+1] = array1[j];
array2[j+1] = array2[j];
}
items[j+1] = value;
}
Using a solution found here to find the new indices after sorting an array, you can apply those indices to array2 like so.
function sortWithIndices(toSort) {
for (var i = 0; i < toSort.length; i++) {
toSort[i] = [toSort[i], i];
}
toSort.sort(function(left, right) {
return left[0] < right[0] ? -1 : 1;
});
toSort.sortIndices = [];
for (var j = 0; j < toSort.length; j++) {
toSort.sortIndices.push(toSort[j][2]);
toSort[j] = toSort[j][0];
}
return toSort;
}
var array1 = ['zzzz', 'aaaa', 'cccc'];
var array2 = [3, 7, 1];
// calculate the indices of array1 after sorting. (attached to array1.sortIndices)
sortWithIndices(array1);
// the final array after applying the sorted indices from array1 to array2
var final = [];
// apply sorted indices to array2
for(var i = 0; i < array1.sortIndices.length; i++)
final[i] = array2[array1.sortIndices[i]];
// output results
alert(final.join(","));
JSFiddle Demo

Categories

Resources