How to compare strings in an array: Javascript - javascript

I have an array which looks like
var arr = ["a|c", "a|e", "x|z"];
for(var x in arr){
var appsplit = x.split("|");
}
If the first value(ex: a) in the elements matches then it should combine the values
Ex: output
ace
xz
Please advice how this approach can be done.

You are testing everyone's reading comprehension with that riddle.
var pairs = {};
var arr = ["a|c", "a|e", "x|z"];
for(var x in arr)
{
var appsplit = arr[x].split("|");
if(pairs[appsplit[0]] !== "undefined")
{
pairs[appsplit[0]] = pairs[appsplit[0]] + appsplit[1];
}
else
{
pairs[appsplit[0]] = appsplit[1];
}
}
var matches = [];
for(var x in pairs)
{
matches.push(x + pairs[x]);
}
console.log(matches);
We need to map out the arr elements in this object called pairs. The first value in your split would be the key and the second value is appended (or assigned if it's the first match to the key)
You made an error of splitting x, but you are only splitting the index of the element, not the actual value of the element. arr[x] is the actual value, where x specifies the index in the array.
After we've gone through your arr, we can now merge the key with the values. Your output is contained in matches where the key in each pair is prepended to the value of the key's pair.

Some simple code that would to the trick here.
var arr = ["a|c", "a|e", "x|z", "c|b", "z|e", "c|a"];
var resultObj = {};
arr.forEach(function(element, index){
var array = element.split('|');
if(array.length!==2){
console.log("skipping, invalid input data", element);
} else {
var firstLetter = array[0];
var secondLetter = array[1];
if(resultObj[firstLetter]){
resultObj[firstLetter].push(secondLetter);
} else {
resultObj[firstLetter]=[secondLetter];
}
}
});
Object.keys(resultObj).forEach(function(key){
console.log(key + "," + resultObj[key]);
});

You can use .reduce(), Set to not accumulate duplicate values, .some() to check if previous array contains value in current array, .map(), Array.from() and .join() to convert array to string
var arr = ["a|c", "a|e", "x|z"];
var res = arr.reduce(function(a, b) {
var curr = b.split("|");
var set = new Set;
for (let prop of curr) set.add(prop);
if (!a.length) {
a.push(set)
} else {
for (prop of a) {
if (curr.some(function(el) {
return prop.has(el)
})) {
for (el of curr) {
prop.add(el)
}
} else {
for (let prop of curr) set.add(prop);
a.push(set)
}
}
}
return a
}, []).map(function(m) {
return Array.from([...m], function(el) {
return el
}).join("")
});
console.log(res);

I feel like this can be done more elegantly, but I didn't have time to streamline it. :) The below code will do what you want, though:
var aStartArray = **ARRAY_VALUE_HERE**;
var aSplitResultStrings = [];
// step through each element in the array
for (var i = 0, iSALength = aStartArray.length; i < iSALength; i++) {
// split the values for the current array element
var aSplitVal = aStartArray[i].split("|");
var bStringDoesNotExist = true;
// loop through the "result strings" array
for (var j = 0, iSRSLength = aSplitResultStrings.length; j < iSRSLength; j++) {
// if the first letter from the array element = the first letter of the current "result string" . . .
if (aSplitResultStrings[j].charAt(0) === aSplitVal[0]) {
// append the second letter of the array value to the current result string
aSplitResultStrings[j] = aSplitResultStrings[j] + aSplitVal[1];
// indicate that a match has been found and exit the "result string" loop
bStringDoesNotExist = false;
break;
}
}
// if there are no result strings that start with the first letter of the array value . . .
if (bStringDoesNotExist) {
// concatenate the two values in the current array value and add them as a new "result string"
aSplitResultStrings.push(aSplitVal[0] + aSplitVal[1]);
}
}
Using these arrays, the results are:
aStartArray = ["a|c", "a|e", "x|z"] //results in:
aSplitResultStrings = ["ace", "xz"]
aStartArray = ["a|b", "a|c", "a|d", "a|e", "x|y", "x|z"] //results in:
aSplitResultStrings = ["abcde", "xyz"]
aStartArray = ["a|b", "d|e", "d|f", "x|y", "g|h", "g|i", "m|n", "g|j", "a|c", "x|z"] //results in:
aSplitResultStrings = ["abc", "def", "xyz", "ghij", "mn"]
As I said, this could be more elegant (for example, you could probably use Map to make iterating through the "result strings" easier), but this makes the steps pretty clear and should get you going down the right path towards a final solution.

Related

Is there an ES6 method to search an array for elements with elements from another array?

I have two arrays containing some parameter values. All elements in the arrays are strings like the following:
x = [ "vorzugsreihe=J", "nennleistung=94,1127", "nenndrehzahl=31,9400"]
y = ["nenndrehzahl=500,3000"]
Expected Output would be:
x = [ "vorzugsreihe=J", "nennleistung=94,1127", "nenndrehzahl=500,3000"]
I have tried using Array.Filter but can't seem to be able to filter only partially (like starting with the string instead of the whole string since that won't match as the values are different).
What I'd like is to be able to go through each element from array Y, and search if the element(string before "=") exists in array X and replace the value(s) of that element in array X.
for(var i=0;i<x.length;i++){
var currentStr = x[i];
var currentInterestedPart = /(.+)=(.+)/.exec(currentStr)[1];
var replacePart = /(.+)=(.+)/.exec(currentStr)[2];
for(var j=0;j<y.length;j++){
if(!y[j].startsWith(currentInterestedPart)) {continue;}
var innerReplacePart = /(.+)=(.+)/.exec(y[j])[2];
x[i] = currentStr.replace(replacePart,innerReplacePart);break;
}
}
Try this. This makes use of RegEx and it is less error prone.
You can use Map and map
First create a Map from array y, split each element by = use first part as key and second part as value
Loop over x array, split each element by = and use first part as key to search in Map if it's present use value from Map else return without any change
let x = ["vorzugsreihe=J", "nennleistung=94,1127", "nenndrehzahl=31,9400"]
let y = ["nenndrehzahl=500,3000"]
let maper = new Map(y.map(v => {
let [key, value] = v.split('=', 2)
return [key, value]
}))
let final = x.map(v => {
let [key, value] = v.split('=', 2)
if (maper.has(key)) {
return key + '=' + maper.get(key)
}
return v
})
console.log(final)
For each value in the y array, iterate and check if the word exist in the x array. Once you find a match just update the value. (The below solution mutates the original array)
const x = [ "vorzugsreihe=J", "nennleistung=94,1127", "nenndrehzahl=31,9400"],
y = ["nenndrehzahl=500,3000"],
result = y.forEach(word => {
let [str, number] = word.split('=');
x.forEach((wrd,i) => {
if(wrd.split('=')[0].includes(str)) {
x[i] = word;
}
});
});
console.log(x);
I'd suggest using combination of reduce + find - this would accumulate and give you the results you're expecting.
var x = [ "vorzugsreihe=J", "nennleistung=94,1127", "nenndrehzahl=31,9400"]
var y = ["nenndrehzahl=500,3000"]
var combinedArr = x.reduce((acc, elem, index) => {
const elemFoundInY = y.find((yElem) => yElem.split("=")[0] === elem.split("=")[0]);
if (elemFoundInY) {
acc = [...acc, ...[elemFoundInY]]
} else {
acc = [...acc, ...[elem]];
}
return acc;
}, [])
console.log(combinedArr);
You can use .startsWith() to check if element start with key= and then replace its value:
let x = [ "vorzugsreihe=J", "nennleistung=94,1127", "nenndrehzahl=31,9400"];
let y = ["nenndrehzahl=500,3000"];
y.forEach(val => {
let [key, value] = val.split("=");
for (let i = 0; i < x.length; i++) {
if (x[i].startsWith(`${key}=`)) x[i] = `${x[i].split("=")[0]}=${value}`;
}
})
console.log(x)
Try this:
y.forEach(item => {
const str = item.split("=")[0];
const index = x.findIndex(el => el.startsWith(str));
if (index) {
const split = x[index].split('=');
x[index] = `${split[0]}=${split[1]}`;
}
})

How do I search a string in JavaScript array using jQuery? [duplicate]

This question already has answers here:
How can I access and process nested objects, arrays, or JSON?
(31 answers)
Closed 6 years ago.
I have a JavaScript array:
var j_array = new Array();
j_arry=["class:1","division:a","class:5","class:3","division:b","division:c","division:d","class:10"];
I need to find how many times the class is coming and its array key, so I use:
found = $.inArray('class', j_array); ` But it returns `-1`;
Then I use:
var search = 'class';
$.each([j_array], function(index, value){
$.each(value, function(key, cell){
if (search.indexOf(cell) !== -1)
console.log('found in array '+index, cell);
});
});
But that is also wrong. How do I solve this?
From this array I want to get the following:
Class coming 4 times, at key 0, 2, 3, and 7
I want to make a separate array of class only, that is,
new_array = ["class:1", "class:2", "class:3", "class:10"];
Currently there are four classes in j_array. How can I get the Nth class value
That is, 1st class value ="class:1", 2nd class value="class:5", etc.
You could filter elements which match in a new array and just return the length of this new array
var j_arry = ["class:1","division:a","class:5","class:3","division:b","division:c","division:d","class:10"];
var res = j_arry.filter(x => x.includes("class"));
var key = res.map(x => x.split(":")[1]);
console.log("Class coming " + res.length + " , at key " + key.join(","));
console.log("new array = ", res);
Use Array.prototype.filter to filter out the elements of the array that contains the string class - see demo below:
var j_array =["class:1","division:a","class:5","class:3","division:b","division:c","division:d","class:10"];
var result = j_array.filter(function(e){
return e.indexOf('class')!==-1;
});
console.log(result);
EDIT:
To get the list of indexes too, you can try this:
var j_array =["class:1","division:a","class:5","class:3","division:b","division:c","division:d","class:10"];
var filteredIndices = []
var filtered = j_array.filter(function(e,i){
if(e.indexOf('class')!==-1) {
filteredIndices.push(i);
return true;
} else {
return false;
}
});
console.log(filtered);
console.log(filteredIndices);
// Nth class value
console.log(filtered[2]); // this prints the 3rd one
.as-console-wrapper{top:0;max-height:100%!important;}
Here is the answer to your questions 1 + 2. It is also 'n' proof so answers your part 3 also. This works by old-fashioned hard graft rather than funky functions. The original array entries are split and filtered then if qualifying we store in an associative array (results) using a pointer array (list) to make it easier to give a sorted result and pull the values from the associative array. The max variable is probably not necessary but included for clarity - could have used list.length instead. Note that the list[] array will be sparse (missing steps) so we test each entry before use in the output steps.
var j_array = new Array();
j_arry=["class:1","division:a","class:5","class:3","division:b","division:c","division:d","class:10","class:1"];
var a, result = [], list=[], max = -1
for (var i =0; i < j_arry.length; i = i + 1) {
var a = j_arry[i].split(":")
if ( a[0] === "class") {
var key = "c" + a[1]
if ( !result[key] ) { result[key] = {pos:[]}}
result[key].cnt = result[key].cnt ? result[key].cnt + 1 : 1;
result[key].pos.push(i)
list[parseInt(a[1])] = "c" + a[1]
max = parseInt(a[1]) > max ? a[1] : max;
}
}
// say locations
for (var i = 0; i < max; i = i + 1) {
if (list[i]) {
key = "c" + i
console.log("Class " + i + " occurs at " + result[key].pos.toString() )
}
}
// make new array
var newArray=[]
for (var i = 0; i < max; i = i + 1) {
if (list[i]) {
newArray.push("Class:" + i)
}
}
console.log("New array=" + newArray.toString() )
Results are:
Class 1 occurs at 0,8
Class 3 occurs at 3
Class 5 occurs at 2
New array=Class:1,Class:3,Class:5
Single reduce is sufficient here.
var arr = ["class:1","division:a","class:5","class:3","division:b","division:c","division:d","class:10"],
res = arr.reduce((p,c) => c.includes("class") ? (p.count++, p.keys.push(c.split(":")[1]), p)
: p ,{count:0, keys:[]});
console.log(res);
You can use the filter and map functions to filter your array to have only elements that match the text 'class', and use array index notation to access the nth element in the array. Check the below code snippet I hope it will be of help to you.
The below code snippet uses ES6 arrow syntax.
var arr = ["class:1", "division:a", "class:5", "class:3", "division:b", "division:c", "division:d", "class:10"];
var result = arr.filter(x => x.indexOf('class') !== -1);
var indices = result.map(x => arr.indexOf(x));
console.log(indices);
console.log(result);
var nValue = window.prompt('Enter n value');
console.log(result[nValue]);
If you're using jQuery to support some really old browser that still don't implement the new Array functions, and you don't want to polyfill those because you're already using jQuery, then you can use the jQuery equivalents:
var arr = ["class:1", "division:a", "class:5", "class:3", "division:b", "division:c", "division:d", "class:10"]
var result = $.grep(arr, function (x) { return x.indexOf('class') !== -1 })
var indices = $.map(result, function (x) { return arr.indexOf(x) })
This is the same code as this answer, but using jQuery.
You have to do map first then filter.
var j_array = ["class:1", "division:a", "class:5", "class:3", "division:b", "division:c", "division:d", "class:10"];
var result = j_array.map(function(e, i) {
return e.indexOf('class') > -1 ? '' + i : false;
}).filter(function(e) {
return !!e;
});
console.log(result);

Find the Words with an even number of occurrences in an Array - Javascript

Given an array of words, write a function that returns an array of the words that occur an even number of times.
function even(["hello", "hi", "hello", "elephant", "hi"]);
That output should be:
["hello", "hi"]
This has been a toy problem I have been struggling with recently. I have solved similar problems counting and returning the number of occurrences of elements in an array but am having trouble taking that logic and applying it to this problem.
This is what I have tried so far, but have hit a wall when trying to output just the even occurrences:
function even(collection) {
var results = [];
for(var i = 0; i < collection.length; i++){
var value = collection[i];
if(results[value]){
results[value] = results[value] + 1;
}else{
results[value] = 1;
}
}
return results;
}
You can use reduce to get an actual count of the words, then simply return an array of the ones that have an even count:
function even(wordsArr) {
//Object of words and counts
var wordCounts = wordsArr.reduce(function(counts, word) {
if (!counts.hasOwnProperty(word)) {
counts[word] = 0;
}
counts[word]++;
return counts;
}, {});
//Now filter that out and return
return Object.keys(wordCounts).filter(function(word) {
return wordCounts[word] % 2 === 0
});
}
even(["hello", "hi", "hello", "elephant", "hi"]); //["hello", "hi"]
var arr = ["hello", "hi", "hello", "elephant", "hi"];
function onlyEvens( arr )
{
var countObj = {};
for( var i = 0; i < arr.length; i++ )
{
var item = arr[i];
if( countObj[ item ] !== undefined )
countObj[item]++;
else
countObj[item] = 1;
}//for()
var filteredArray = [];
for(var key in countObj )
{
if( countObj[key] % 2 == 0 )
filteredArray.push( key );
}
return filteredArray;
}//onlyEvens()
console.log( onlyEvens( arr ) );
Issues in your code:
you use collection instead of words
you cannot access array the associative way. You must declare it as object:
results[value]
you return result variable, but it is undeclared.
return result;
results only contains the occurrences of every word. There miss the code that calculates if the occurrences of a word are odd or even.
fixed code:
function even(words) { // <<< in your code was collection
var results = {};
for(var i = 0; i < words.length; i++){
var value = words[i];
if(results[value]){
results[value] = results[value] + 1;
}else{
results[value] = 1;
}
}
var ret = [];
for(var word in results)
if(results[word]%2 !== 0)
rest.push(word);
return ret;
}
function even(list) {
var d = list.reduce(function(d, w) { d[w] = !d[w]; return d; }, {});
return Object.keys(d).filter(function(w) { return !d[w]; });
}
console.log(even(["hello", "hi", "hello", "elephant", "hi"]));
console.log(even(["hello", "yo", "yo", "hi", "hello", "yo", "elephant", "hi"]));
Explanation: Use the array .reduce() method to create an object (d) with a property for each word (w) with a boolean value indicating whether the word has an odd number of occurrences. Then .filter() the keys to get all the ones that are not odd.
If you previously sort the array you can filter it as required in just a code line like this :
var even = (str) => str.sort().filter((element, index, arr) => index+1 === arr.lastIndexOf(element));
console.log(even(["hello", "hello", "hi", "elephant", "hi", "hi"])); //[ 'hello', 'hi' ]

Loop thru a string with numbers and symbols & push to array

I'm trying to loop thru a string with numbers that has a symbol inside, I want the numbers before the symbol to be pushed to an array then the symbol to another array and then get the rest of the numbers after the symbol pushed to a 3rd array.
var myString = "1234*5678";
var number1 = [];
for (i = 0; i < myString.length; i++) {
if (isNaN(myString[i]) === false) {
var firstSet = number1.push(myString[i]);
}
};
var mySymbol = [];
for (j = number1[0]; j < myString.length; j++) {
if (isNaN(myString[j]) === true) {
var mathematics = mySymbol.push(myString[j])
document.write(mySymbol[0])
}
};
when I document.write the "mySymbol" variable it gives the desired result, but when I call the "number1" variable it gives me the numbers from before and after the symbol I only want the numbers before the symbol to be pushed to the array, also how do I write the 3rd loop to get the numbers after the symbol pushed to a new array?
try
var arr=[[],[],[]]
index = 0
"1234*5678".split('').forEach(function(e){
if(parseInt(e)){
arr[index].push(e);
}else{
index ++;
arr[index++].push(e)
}
});
document.write('First Array ' +arr[0] + '<br>');
document.write('Secont Array ' +arr[1] + '<br>');
document.write('Third Array ' +arr[2]);
You could try using:
var myString = '1234*5678';
var resultArr = myString.match(/([a-zA-Z0-9]+)([^a-zA-Z0-9])([a-zA-Z0-9]+)/);
To get the string before symbol:
var myFirstSet = resultArr[1];
To get symbol:
var mySymbol = resultArr[2];
To get the string after symbol:
var mySecondSet = resultArr[3];
To convert each of these three groups into their own arrays:
var result = [];
resultArr
.slice(1)
.forEach(
function(s){
result.push(s
.split('')
.map(
function(n){
return parseInt(n) || n;
}
)
)
}
);
The following code accomplishes the goal:
var str = '1234*5678';
var arr = str.match(/([a-zA-Z0-9]+)|\*/g);
console.log(arr[0], arr[1], arr[2]);
http://jsfiddle.net/hp2ohvzb/

push only unique elements in an array

I have array object(x) that stores json (key,value) objects. I need to make sure that x only takes json object with unique key. Below, example 'id' is the key, so i don't want to store other json objects with 'item1' key.
x = [{"id":"item1","val":"Items"},{"id":"item1","val":"Items"},{"id":"item1","val":"Items"}]
var clickId = // could be "item1", "item2"....
var found = $.inArray(clickId, x); //
if(found >=0)
{
x.splice(found,1);
}
else{
x.push(new Item(clickId, obj)); //push json object
}
would this accomplish what you're looking for? https://jsfiddle.net/gukv9arj/3/
x = [
{"id":"item1","val":"Items"},
{"id":"item1","val":"Items"},
{"id":"item2","val":"Items"}
];
var clickId = [];
var list = JSON.parse(x);
$.each(list, function(index, value){
if(clickId.indexOf(value.id) === -1){
clickId.push(value.id);
}
});
You can't use inArray() because you are searching for an object.
I'd recommend rewriting a custom find using Array.some() as follows.
var x = [{"id":"item1","val":"Items"},{"id":"item1","val":"Items"},{"id":"item1","val":"Items"}]
var clickId = "item1";
var found = x.some(function(value) {
return value.id === clickId;
});
alert(found);
Almost 6 years later i ended up in this question, but i needed to fill a bit more complex array, with objects. So i needed to add something like this.
var values = [
{value: "value1", selected: false},
{value: "value2", selected: false}
//there cannot be another object with value = "value1" within the collection.
]
So I was looking for the value data not to be repeated (in an object's array), rather than just the value in a string's array, as required in this question. This is not the first time i think in doing something like this in some JS code.
So i did the following:
let valueIndex = {};
let values = []
//I had the source data in some other and more complex array.
for (const index in assetsArray)
{
const element = assetsArray[index];
if (!valueIndex[element.value])
{
valueIndex[element.value] = true;
values.push({
value: element.value,
selected: false
});
}
}
I just use another object as an index, so the properties in an object will never be repated. This code is quite easy to read and surely is compatible with any browser. Maybe someone comes with something better. You are welcome to share!
Hopes this helps someone else.
JS objects are great tools to use for tracking unique items. If you start with an empty object, you can incrementally add keys/values. If the object already has a key for a given item, you can set it to some known value that is use used to indicate a non-unique item.
You could then loop over the object and push the unique items to an array.
var itemsObj = {};
var itemsList = [];
x = [{"id":"item1","val":"foo"},
{"id":"item2","val":"bar"},
{"id":"item1","val":"baz"},
{"id":"item1","val":"bez"}];
for (var i = 0; i < x.length; i++) {
var item = x[i];
if (itemsObj[item.id]) {
itemsObj[item.id] = "dupe";
}
else {
itemsObj[item.id] = item;
}
}
for (var myKey in itemsObj) {
if (itemsObj[myKey] !== "dupe") {
itemsList.push(itemsObj[myKey]);
}
}
console.log(itemsList);
See a working example here: https://jsbin.com/qucuso
If you want a list of items that contain only the first instance of an id, you can do this:
var itemsObj = {};
var itemsList = [];
x = [{"id":"item1","val":"foo"},
{"id":"item2","val":"bar"},
{"id":"item1","val":"baz"},
{"id":"item1","val":"bez"}];
for (var i = 0; i < x.length; i++) {
var item = x[i];
if (!itemsObj[item.id]) {
itemsObj[item.id] = item;
itemsList.push(item);
}
}
console.log(itemsList);
This is late but I did something like the following:
let MyArray = [];
MyArray._PushAndRejectDuplicate = function(el) {
if (this.indexOf(el) == -1) this.push(el)
else return;
}
MyArray._PushAndRejectDuplicate(1); // [1]
MyArray._PushAndRejectDuplicate(2); // [1,2]
MyArray._PushAndRejectDuplicate(1); // [1,2]
This is how I would do it in pure javascript.
var x = [{"id":"item1","val":"Items"},{"id":"item1","val":"Items"},{"id":"item1","val":"Items"}];
function unique(arr, comparator) {
var uniqueArr = [];
for (var i in arr) {
var found = false;
for (var j in uniqueArr) {
if (comparator instanceof Function) {
if (comparator.call(null, arr[i], uniqueArr[j])) {
found = true;
break;
}
} else {
if (arr[i] == uniqueArr[j]) {
found = true;
break;
}
}
}
if (!found) {
uniqueArr.push(arr[i]);
}
}
return uniqueArr;
};
u = unique(x, function(a,b){ return a.id == b.id; });
console.log(u);
y = [ 1,1,2,3,4,5,5,6,1];
console.log(unique(y));
Create a very readable solution with lodash.
x = _.unionBy(x, [new Item(clickId, obj)], 'id');
let x = [{id:item1,data:value},{id:item2,data:value},{id:item3,data:value}]
let newEle = {id:newItem,data:value}
let prev = x.filter(ele=>{if(ele.id!=new.id)return ele);
newArr = [...prev,newEle]

Categories