Sort an array by string value - javascript

How can I sort an array by string value?
If I have an array such as ['you', 'I', 'me', 'me', 'will', 'me'], how can I get all the indexes with the word me at the front of the array?
I have tried using array.sort, but it does not seem to be working.
e.target.value is the an value I am getting from a <select element in the dom.
arr.sort((a, b) => {
if (a < e.target.value) {
return -1;
}
if (a > e.target.value) {
return 1;
}
return 0;
});
UPDATE:
Yury's answer works very well, but what if I need to match two values in an array of objects and have those sorted.
Example:
arr = [
{id: 1, name: "cookie"},
{id: 2, name: 'foo'},
{id: 3, name: 'bar'},
{id: 2, name: 'foo'}
];
How can I place all the elements with the id '2' and with the name 'foo' at the front of the array?

You could use sort
let a = ['you', 'I', 'me', 'me', 'will', 'me'];
a.sort((a, b) => a !== b && b === 'me' ? 1 : 0);
console.log(a)

const arr = [
{id: 1, name: "cookie"},
{id: 2, name: 'foo'},
{id: 3, name: 'bar'},
{id: 2, name: 'foo'}
];
Use the Array.prototype.sort() method on arr using a callback function that switches the order of items only if the first one does not match the given criteria and the second one does.
arr.sort((item1, item2) => {
if((item1.id !== 2 || item1.name !== 'foo') && (item2.id === 2 || item2.name === 'foo')) {
return 1;
}
return 0;
});
console.log(arr);

Related

How to merge two object TypeScript?

I have two objects:
let a = [{id: 1, selected: false, key: "plan"}];
let b = [{id: 1, selected: true, key: "plan", "text": "aaaa"}, {id: 2, selected: true}];
I need to merge them and get:
let c = [{id: 1, selected: true, key: "plan", "text": "aaaa"}, {id: 2, selected: true}];
My main purpose to rewrite default object on modified
I have tried:
let c = {...a, ...b};
You can use reduce in order to replace the data that is being fetched from server.
Below I have simulated different scenarios considering a as the original array and b & c as the responses from the server
let a = [{ id: 1, selected: false, key: 'plan' }];
let b = [
{ id: 1, selected: true, key: 'plan', text: 'aaaa' },
{ id: 2, selected: true },
];
const mergeArrays = (array1, array2) => {
array2 = array2 || [];
array1 = array1 || [];
return Object.values([...array1, ...array2].reduce((result, obj) => {
result = {
...result,
[obj.id]: {...obj}
}
return result;
}, {}))
};
//Consider you got the response from server
//a -> Original array, b -> Response from serer
console.log(mergeArrays(a, b))
//Response from server is null or []
console.log(mergeArrays(a, null))
//original array is empty but there's a response from server
console.log(mergeArrays([], b))
//Consider there is completely a different object in the array received from the server than the one defined in the original array
let c = [{ id: 2, selected: true, key: 'plan' }];
console.log(mergeArrays(a, c))
.as-console-wrapper {
max-height: 100% !important;
}
Hope this helps.
you must first determine which one is biggest then, if b is bigger than a:
let a = [{id: 1, selected: false, key: "plan"}];
let b = [{id: 1, selected: true, key: "plan", "text": "aaaa"}, {id: 2, selected: true}];
let bigger = a.length > b.length ? a : b;
let shorter = a.length < b.length ? a : b;
console.log(bigger.map(x => ({...x, ...shorter.find(y => y.id === x.id)})))
You can use destructure:
let c = [...a,...b];

Sorting JSON array with nulls in JavaScript

My JSON array
var jData = [
{id: 1, parent: null},
{id: 2, parent: null},
{id: 3, parent: 1},
{id: 4, parent: 2},
{id: 5, parent: 2},
{id: 6, parent: 1}];
I want this be to sorted like the following ( by id then by the parent )
[
{id: 1, parent: null},
{id: 3, parent: 1},
{id: 6, parent: 1}
{id: 2, parent: null},
{id: 4, parent: 2},
{id: 5, parent: 2},
];
What is the best way to do it in JavaScript?
I tried, but no luck
jData .sort((a, b) => a.id - b.id ||a.parent- b.parent);
Help!!
You need a topological sorting first and then take the nodes in order of appearance.
function getData(array) {
return array.flatMap(({ data, children = [] }) => [data, ...getData(children)]);
}
var data = [{ id: 1, parent: null }, { id: 2, parent: null }, { id: 3, parent: 1 }, { id: 4, parent: 2 }, { id: 5, parent: 2 }, { id: 6, parent: 1 }],
tree = function (data, root) {
var t = {};
data.forEach(data => {
Object.assign(t[data.id] = t[data.id] || {}, { data });
t[data.parent] = t[data.parent] || {};
t[data.parent].children = t[data.parent].children || [];
t[data.parent].children.push(t[data.id]);
});
return t[root].children;
}(data, null),
result = getData(tree);
console.log(result);
console.log(tree); // just to show what's happening
.as-console-wrapper { max-height: 100% !important; top: 0; }
If parent is null we use the id as parent value and sort by parent first (otherwise we won't reach your result). If the parent value comparison results in zero, we sort by id.
var jData = [{id:5,parent:2},{id:1,parent:null},{id:4,parent:2},{id:2,parent:null},{id:3,parent:1},{id:6,parent:1}];
let res = jData.sort((a,b) => {
let ap = a.parent ? a.parent : a.id,
bp = b.parent ? b.parent : b.id;
return ap - bp || a.id - b.id;
});
console.log(res);
You can use reduce to group each array to its parent. Use 0 if parent is null. Use another reduce to contruct the final array.
var jData = [{"id":1,"parent":null},{"id":2,"parent":null},{"id":3,"parent":1},{"id":4,"parent":2},{"id":5,"parent":2},{"id":6,"parent":1}]
var temp = jData.reduce((c, v) => {
let p = v.parent || 0;
c[p] = c[p] || [];
c[p].push(v);
return c;
}, {});
var newjData = temp[0].reduce((c, v) => {
var o = temp[v.id] || [];
o.sort((a, b) => a.id - b.id); //Sort. Incase the IDs are not in order in the original array.
c.push(v, ...o);
return c;
}, []);
console.log(newjData);

Sort an array by its relative position

Example object array:
[{
id: 'a',
beforeId: null
}, {
id: 'b',
beforeId: 'c'
}, {
id: 'c',
beforeId: 'a'
}, {
id: 'd',
beforeId: 'b'
}]
Output order: d-b-c-a; each element sorted relative to each other element based on its beforeId property.
I could make a temporary array and sort the above array. Is sorting possible with array.sort?
You could build an object with the relations and generate the result by using the object with beforeId: null and unshift all objects for the result array.
The next object is the one with the actual val as key.
Complexity: O(2n).
function chain(array) {
var o = {}, pointer = null, result = [];
array.forEach(a => o[a.beforeId] = a);
while (o[pointer]) {
result.unshift(o[pointer]);
pointer = o[pointer].val;
}
return result;
}
var data = [{ val: 'a', beforeId: null }, { val: 'b', beforeId: 'c' }, { val: 'c', beforeId: 'a' }, { val: 'd', beforeId: 'b' }];
console.log(chain(data));
.as-console-wrapper { max-height: 100% !important; top: 0; }
This is a terribly inefficient and naïve algorithm, but it works:
const array = [
{id: 'a', beforeId: null},
{id: 'b', beforeId: 'c'},
{id: 'c', beforeId: 'a'},
{id: 'd', beforeId: 'b'}
];
// find the last element
const result = [array.find(i => i.beforeId === null)];
while (result.length < array.length) {
// find the element before the first element and prepend it
result.unshift(array.find(i => i.beforeId == result[0].id));
}
console.log(result);
Is sorting possible with array.sort?
sure, with a helper function:
graph = [
{id: 'a', beforeId: null},
{id: 'b', beforeId: 'c'},
{id: 'c', beforeId: 'a'},
{id: 'd', beforeId: 'b'}
];
let isBefore = (x, y) => {
for (let {id, beforeId} of graph) {
if (id === x)
return (beforeId === y) || isBefore(beforeId, y);
}
return false;
};
graph.sort((x, y) => x === y ? 0 : (isBefore(x.id, y.id) ? -1 : +1))
console.log(graph);
isBefore returns true if x is before y immediately or transitively.
For generic, non-linear topological sorting see https://en.wikipedia.org/wiki/Topological_sorting#Algorithms
UPD: As seen here, this turned out to be horribly inefficient, because sort involves many unnecessary comparisons. Here's the fastest (so far) version:
function sort(array) {
let o = {}, res = [], len = array.length;
for (let i = 0; i < len; i++)
o[array[i].beforeId] = array[i];
for (let i = len - 1, p = null; i >= 0; i--) {
res[i] = o[p];
p = o[p].id;
}
return res;
}
which is the #Nina's idea, optimized for speed.
You may try this approach :
// order(null, vals, []) = ["d", "b", "c", "a"]
function order(beforeId, vals, result){
var id = beforeId || null;
var before = vals.filter(function(val){
return val.beforeId === id
});
if (before.length === 0) return result;
return order(before[0].val,
vals,
[before[0].val].concat(result));
}

Get an item in an array to first position according to a condition

Hey I have the following array :
var ar = [{id: "F"}, {id: "G"}, {id: "Z"}, {id: "ZZ"}]
I would like to move the one with the id equals to ZZ to the first position in the array.
I know how to do it using several different functions, but I was wondering if there was an elegant solution to do it (lodash, ...)
You could use unshift() to add to start of array and splice() and findIndex() to get object by id.
var arr = [{id: "F"}, {id: "G"}, {id: "Z"}, {id: "ZZ"}]
arr.unshift(arr.splice(arr.findIndex(e => e.id == "ZZ"), 1)[0])
console.log(arr)
var ar = [{
id: "F"
}, {
id: "G"
}, {
id: "Z"
}, {
id: "ZZ"
}];
ar.sort(function(a, b) {
if (a.id === "ZZ") {
return -1;
}
if (b.id === "ZZ") {
return 1;
}
return 0;
});
console.log(ar);
How about sorting it?

Filter the original array of objects by array of ids

I have two arrays:
array a:
var a = [
{
id: 1,
name: 'a'
},
{
id: 2,
name: 'b'
},
{
id: 3,
name: 'c'
}
];
array ids:
var ids = [1];
I want to array a filtered by array ids, result i wanted:
var a = [
{
id: 1,
name: 'a'
}
];
The most important thing is i want the change on the original array, rather than return a new array.
underscore solution is better:)
You can use .filter
a = a.filter(function(el){
return ~ids.indexOf(el.id)
});
// should give you [{id: 1, name: 'a'}]
Today I tried to solve similar task (filtering the original array of objects without creating a new array) and this is what I came up with:
const a = [{ id: 1, name: 'a'}, { id: 2, name: 'b'}, { id: 3, name: 'c'}];
const ids = [1];
Array.from(Array(a.length).keys()).reverse().forEach(index =>
!ids.some(id => id === a[index].id) && a.splice(index, 1)
);
console.log(a); // [{ id: 1, name: 'a'}]
The point is that we need to loop back through the original array to be able to use Array.prototype.splice, but I didn't want the for-loop, I wanted to have ES6 one-liner. And Array.from(Array(a.length).keys()).reverse() gives me a list of reversed indexes of the original array. Then I want to splice the original array by current index only if the corresponding item's id is not present in the ids array.

Categories

Resources