Sort array elements on JavaScript - javascript

I have an array, each subarray of which contains different positions in different order:
[
["apple(2)", "banana(5)"],
["peach(3)", "banana(1)"],
["apple(1)"]
]
I need to sort it on JavaScript (ES6) and i expect to get an array like this:
[
["apple(2)", "banana(5)", "peach(0)"],
["apple(0)", "banana(1)", "peach(3)"],
["apple(1)", "banana(0)", "peach(0)"]
]
Order of each subarray should be the same. If subarray don't have some position, i need to add it with 0 value. Can i using something like map() or sort() function or need to compare it manually?

Here is functional programming approach, using a Map and reduce:
const data = [['apple(2)', 'banana(5)'],['peach(3)', 'banana(1)'],['apple(1)'],];
// Create a Map with default values for each name, i.e. with "(0)":
let names = new Map(data.flat().map(item => [item.replace(/\d+/, ""), item.replace(/\d+/, "0")]));
let result = data.map(row =>
[...row.reduce((map, item) =>
map.set(item.replace(/\d+/, ""), item), // Overwrite default
new Map(names) // Start with clone of original Map
).values()]
);
console.log(result);

You have to loop over to get the keys used. You then have to loop over a second time to get the fill in the missing keys. There are many ways of doing it, this is one.
var data = [
["apple(2)", "banana(5)"],
["peach(3)", "banana(1)"],
["apple(1)"]
];
// match string and number
var re = /([^(]+)\((\d+)\)/;
// Loop over and find all of the keys
var grouped = data.reduce((info, subset, index) => {
subset.forEach(item => {
// find the key and count
var parts = item.match(re);
// have we seen this key?
if (!info[parts[1]]) {
// if not create an array
info[parts[1]] = Array(data.length).fill(0);
}
// set the key index with the count
info[parts[1]][index] = parts[2];
})
return info;
}, {});
// loop over the groups and fill in the set
Object.entries(grouped).forEach(([key, counts], colIndex) => {
counts
.forEach((cnt, rowIndex) => {
data[rowIndex][colIndex] = `${key}(${cnt})`;
})
});
console.log(data);

First get the unique words. Then traverse array of arrays to check if the word is present or not. If it is not present then make the word according to your condition and if present then put the original word to the tmp array. At last sort it for each iteration. By the way, I used regex replace method to get the word.
const data = [
['apple(2)', 'banana(5)'],
['peach(3)', 'banana(1)'],
['apple(1)'],
];
const words = [...new Set(data.flat().map((x) => x.replace(/[^a-z]/gi, '')))];
const ret = data.map((x) => {
const tmp = [];
const newX = x.map((y) => y.replace(/[^a-z]/gi, ''));
for (let i = 0, l = words.length; i < l; i += 1) {
if (newX.includes(words[i])) tmp.push(x.shift());
else tmp.push(`${words[i]}(0)`);
}
return tmp.sort();
});
console.log(ret);

Related

How does one, for nested arrays, rearrange the order in a way that the last string item of an array equals the first string item of the following one?

I need to achieve this result
[['peanuts', 'butter'], ['butter', 'jelly'], ['jelly', 'bananas'], ['bananas', 'apples']]
From this array
[['butter', 'jelly'], ['bananas', 'apples'], ['peanuts', 'butter'], ['jelly', 'bananas']]
I want the second element of each array to match the first element of the next one.
I think sort function is the best option here, but I have tried this and this doesn't work (actually works but not with all arrays somehow)
.sort(([a, b], [c, d]) => {
return b === c ? -1 : 1
})
Sorting is not the best method to solve this problem. Instead, you can create lookup tables for the first and second elements and go through them in sequence.
const arr = [
['butter', 'jelly'],
['bananas', 'apples'],
['peanuts', 'butter'],
['jelly', 'bananas']
];
const lookupFirst = {},
lookupSecond = {};
for (let i = 0; i < arr.length; i++) {
lookupFirst[arr[i][0]] = i;
lookupSecond[arr[i][1]] = i;
}
const next = arr.map(x => lookupFirst[x[1]]);
let curr = arr.findIndex(x => !lookupSecond[x[0]]);
const res = [];
do {
res.push(arr[curr]);
} while ((curr = next[curr]) !== undefined);
console.log(JSON.stringify(res));
Sorting will not help, instead one needs an algorithm which, for instance, starts by searching for the only array that does not have any matching item which links it to any of the other arrays.
This array's first item (a string) then is the link to this very arrays previous array that's last item does match the before mentioned first item.
The above described process splices every matching array from the input value and collects (unshift) them within a result array, thus it mutates the input value, and therefore just needs to be continued until the input value got emptied.
function getCopyInDominoesLikeOrder(list) {
// in order to not directly mutate the input value.
list = Array.from(list);
// get the array where its last item does not match
// any other array's first item, which makes it the
// last array of the return value.
let itemListIndex = list.findIndex(aList =>
list.every(bList => aList[aList.length - 1] !== bList[0])
);
let itemList = list.splice(itemListIndex, 1)[0];
const result = [itemList]; // return value.
let firstItem = itemList[0];
// mutate/reduce the input value's copy while looking
// for the array where its last item matches the first
// item of the previously found/extracted (linked) array.
while (list.length !== 0) {
itemListIndex = list.findIndex(aList =>
aList[aList.length - 1] === firstItem
);
itemList = list.splice(itemListIndex, 1)[0]; // mutate/reduce.
result.unshift(itemList); // aggregate return value.
firstItem = itemList[0];
}
return result;
}
const arr = [
['butter', 'jelly'],
['bananas', 'apples'],
['peanuts', 'butter'],
['jelly', 'bananas'],
];
console.log(
'original :: arr :',
arr
);
console.log(
'sorted :: getCopyInDominoesLikeOrder(arr) :',
getCopyInDominoesLikeOrder(arr)
);
.as-console-wrapper { min-height: 100%!important; top: 0; }
It looks like you only need to extract the first element from each array in the sort callback, then return the lexiographic difference:
const arr = [['c','d'], ['a','b'], ['d','e'], ['b','c']];
arr.sort((a, b) => a[0].localeCompare(b[0]));
console.log(arr);
.sort(([a], [b]) => a > b)

while pushing the data in to arrays, not added in order

enter image description here
i need to push the data one after another, but here i am getting to add in disorder like last added array in to first.
for (var key in data[tabName + scoreBreakDown]) {
var values = data[tabName + scoreBreakDown][key];
var staticData = values[0];
var obj = [];
obj.push(staticData.CompanyName);
obj.push(staticData.Country_ORIG);
for (var value in values) {
if (addHeader) {
headersArray.push(values[value].AspectName);
weightArray.push(values[value].ScoreWeight);
}
obj.push(values[value].SPESGScore_ORIG);
}
addHeader = false;
dataArray.push(obj);
}
You can use array.map to map through an array and transform it into a new array in order.
In this example, we are just multiplying each value by 3, but the transformation is arbitrary.
let loop = (arr) => {
return arr.map(item => {
return item*3
})
}
console.log(loop([1,2,3,4,5]))
If you want to loop through an object in order this way, you can use Object.keys() this will return an array of the keys in the object.
let loop = (obj) => {
return Object.keys(obj).map(item => {
return `${item}: ${obj[item]}`
})
}
let obj = {
first_name:"John",
last_name:"Doe",
age:23
}
console.log(loop(obj))
So instead of using a for loop and an if statement to check a condition and push the data to the array after each iteration, you can use something Array.filter() to remove entries you don't want to push, and return them in order.
data = [
{header:true, value:"item1"},
{header:false, value:"item2"},
{header:true, value:"item3"},
]
let array = data.filter(item => {return item.header}).map(item => {
return item.value
})
console.log(array)

Remove duplicate index value from first array, manipulate second as per first(at some specific conditions)

This is the tricky one :
please understand my scenario:
I have two array , both array will have equal length always.
I want remove duplicate value in first array and second array will be manipulated according first one.
like if i have array like :
var firstArr = [1,1,4,1,4,5]
var secArr = ['sagar', 'vilas', 'suraj', 'ganesh','more','abhi']
//I want below Output
//[1,4,5] // this is firstArr after manipulation
//['sagar|vilas|ganesh','suraj|more',abhi] // this is secArr after manipulation
// here all duplicate values will be removed from first array
// and at same index second array will be manipulated.
please check my fiddle:
https://jsfiddle.net/abhilash503001/du4fe8ob/86/
You can use Map and reduce
First loop through the first array and map it values as key and take the values from second array's respective index as key
Now you have loop on the map's entries take the key's will be your unique firstArr and to get desired value for second arr you need to join values by |
var firstArray = [1,1,4,1,4,5]
var secArr = ['sagar', 'vilas', 'suraj', 'ganesh','more','abhi']
let op = firstArray.reduce((op,inp,index) => {
if(op.has(inp)){
let val = op.get(inp)
val.push(secArr[index])
op.set(inp, val)
} else {
op.set(inp,[secArr[index]])
}
return op
},new Map())
let {firstArr, secondArr} = [...op.entries()].reduce((op,[first,second])=>{
op.firstArr.push(first)
op.secondArr.push(second.join('|'))
return op
},{firstArr:[],secondArr:[]})
console.log(firstArr)
console.log(secondArr)
This is how I did it.
You first group the texts into arrays and then join them together.
var index_array = [1,1,4,1,4,5]
var text_array = ['sagar', 'vilas', 'suraj', 'ganesh','more','abhi'];
var manipulated_text_array = [];
var manipulated_index_array = [];
var groups = {};
for (let index in index_array) {
if (groups[index_array[index]] == undefined) {
groups[index_array[index]] = [];
}
groups[index_array[index]].push(text_array[index]);
}
for (let index in groups) {
manipulated_text_array.push(groups[index].join("|"));
}
manipulated_index_array = Object.keys(groups).map(x => parseInt(x));
console.log("texts", manipulated_text_array);
console.log("indexes", manipulated_index_array);

Alphabetically sort array with no duplicates

I'm trying to create a function that takes an array of strings and returns a single string consisting of the individual characters of all the argument strings, in alphabetic order, with no repeats.
var join = ["test"];
var splt = (("sxhdj").split(""))
var sort = splt.sort()
var jn = sort.join("")
join.push(jn)
function removeDuplicates(join) {
let newArr = {};
join.forEach(function(x) { //forEach will call a function once for
if (!newArr[x]) {
newArr[x] = true;
}
});
return Object.keys(newArr);
}
console.log(removeDuplicates(join));
I can not get the current code to work
Check out the comments for the explanation.
Links of interest:
MDN Array.prototype.sort.
MDN Set
var splt = ("sxhdjxxddff").split("")
// You need to use localeCompare to properly
// sort alphabetically in javascript, because
// the sort function actually sorts by UTF-16 codes
// which isn't necessarily always alphabetical
var sort = splt.sort((a, b)=>a.localeCompare(b))
// This is an easy way to remove duplicates
// by converting to set which can't have dupes
// then converting back to array
sort = [...new Set(sort)]
var jn = sort.join("");
console.log(jn);
Something like this :) Hope it helps!
const string = 'aabbccd';
const array = string.split('');
let sanitizedArray = [];
array.forEach(char => {
// Simple conditional to check if the sanitized array already
// contains the character, and pushes the character if the conditional
// returns false
!sanitizedArray.includes(char) && sanitizedArray.push(char)
})
let result = sanitizedArray.join('')
console.log(result);
Try this:
const data = ['ahmed', 'ghoul', 'javscript'];
const result = [...data.join('')]
.filter((ele, i, arr) => arr.lastIndexOf(ele) === i)
.sort()
.join('');
console.log(result)
There are probably better ways to do it, one way is to map it to an object, use the keys of the object for the used letters, and than sorting those keys.
const words = ['foo', 'bar', 'funky'];
const sorted =
Object.keys(
([...words.join('')]) // combine to an array of letters
.reduce((obj, v) => obj[v] = 1 && obj, {}) // loop over and build hash of used letters
).sort() //sort the keys
console.log(sorted.join(''))

How to check if any of the strings from an array with variable length are present in another string?

I am trying to filter some data from an array in a JSON file, based on an input of the form string1, string1,string2, string1,string2,string3 etc., that is, some strings separated by a ,.
What I'm trying to do:
let arrInput = document.getElementById('inputBox').val.split(',');
for(let i = 0; i < arrToFilter.length; i++){
if(.........what to write here?...........){
arrOutput.push(arrToFilter[i]);
}
}
return arrOutput;
If the arrInput had a fixed length, I could accomplish this using indexOf != -1 for each element in arrInput, but here, since the length of arrInput is variable, how can I check if at least one of the strings present in arrInput is also present as a substring in arrToFIlter[i]?
Edit:
Example:
Let arrToFilter be ["abcqwer", "pizza", "definition", "abcdef", "example"]
Case 1 :
Say the input entered (in an <input> element) is abc,def.
For this, the arrOutput should be ["abcqwer", "definition", "abcdef"]
Case 2:
Say the input entered is abc
Expected output : ["abcqwer", "abcdef"]
Simple way is using some and filter,
var string = 'ad,kk,sb';
var array = ['adik', 'klop', 'pp'];
var stringers = string.split(',');
var result = array.filter((arr) => {
var isPresent = stringers.some(stringer => arr.includes(stringer));
return isPresent ? true : false;
});
console.log(result);
You need to iterate both arrays
let arrToFilter = ['abcqwer', 'pizza', 'definition', 'abcdef', 'example'];
let arrOutput = [];
let arrInput = document.getElementById('inputBox').value.split(',');
arrToFilter.forEach(filter => {
arrInput.forEach(input => {
if (!!input && filter.includes(input)) {
arrOutput.push(filter);
}
});
});
// distinct the output
return arrOutput.filter((v, i, a) => i === a.indexOf(v));

Categories

Resources