Extract all words from fields of objects inside array - javascript

i have this array:
array = [{"full_name":"louis jackson","title1":"english teacher,"description":"good and nice teacher"},{"full_name":"peter carey","title1":"math teacher,"description":"bad and ugly teacher"}]
i need to get this array
results = ["louis","jackson","english", "teacher",good","and","nice","teacher","peter","carey","math","teacher","bad","and","ugly","teacher"]
i have tried:
results = [];
array.forEach(item => {
results.push (item.full_name.split(" "));
results.push (item.title1.split(" "));
results.push (item.description.split(" "));
}
i just get multiple separated arrays; can anyone guide me in right way?

I made a bit of clean code to do it all for you
array = [{"full_name":"louis jackson","title1":"english teacher","description":"good and nice teacher"},{"full_name":"peter carey","title1":"math teacher","description":"bad and ugly teacher"}]
var results = array.flatMap(obj => {
const vals = Object.values(obj);
return vals.flatMap(val => val.split(' '));
})
console.log(results);
Object.values just gets the value from each property of each object, so you're not dealing with the keys like 'full_name' or 'title1'
Then once you have the values, you split them by the space and return them as an array.
flatMap makes sure that if you return an array of arrays, it flattens it 1 layer.
edit -- here's it as a one liner:
var results = array.flatMap(obj => Object.values(obj).flatMap(val => val.split(' ')));

Assuming the values are always strings and probably the words could be separated by multiple spaces:
This v.split(/ +/) splits each phrase as an array of strings which will be concatenated to the main array (the accumulator in the reduce function).
let array = [{"full_name":"louis jackson","title1":"english teacher","description":"good and nice teacher"},{"full_name":"peter carey","title1":"math teacher","description":"bad and ugly teacher"}];
let result = array.reduce((a, c) => {
Object.values(c).forEach(v => a = a.concat(v.split(/ +/)));
return a;
}, []);
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }

Your solution is close, but you just have to concat the arrays instead of pushing the split arrays into results. Like this:
let array = [{"full_name":"louis jackson","title1":"english teacher","description":"good and nice teacher"},{"full_name":"peter carey","title1":"math teacher","description":"bad and ugly teacher"}]
let results = [];
array.forEach(item => {
results = results.concat(item.full_name.split(" "))
.concat(item.title1.split(" "))
.concat(item.description.split(" "));
});
console.log(results);
Here's another take using for..of and for..in so you don't need to manually define the property names:
let array = [{"full_name":"louis jackson","title1":"english teacher","description":"good and nice teacher"},{"full_name":"peter carey","title1":"math teacher","description":"bad and ugly teacher"}]
let results = [];
for(const item of array)
for(const prop in item)
results.push(...item[prop].split(" "))
console.log(results);

result is an empty array. The split() method returns an array. When you call push() on an array, you're adding an array to an array. Every time you call push, you add another array to the array. So you have an array of arrays. What you want is a single array with all the values.
So call split() on each value to get an array, iterate through the values, then call push() on the values of the array, not the array itself.
Try this
var results = [];
array.forEach(item => {
var names = item.full_name.split(" ");
names.forEach(i => result.push(i));
var titles = item.title1.split(" ");
titles.forEach(t => result.push(t));
}
You can take #Klaycon advice and use
.concat() instead of forEach loop.
If you're not using an older version of IE you can use ... assign operator.

Related

Javascript join array with brackets

In javascript I need to join an array into a string with brackets. For example ['abc', 'yte', 'juu'] => (abc)(yte)(juu). I need the fastest and cleanest way to do this. I tried using the array join operator but it doesnt work on the first and last element.
You can do it with template literals. Use join() with )( separator, and wrap the result with ():
const data = ['abc', 'yte', 'juu'];
const result = `(${data.join(')(')})`;
console.log(result);
Thinking "I need the fastest and cleanest way to do this." is often not ideal. In most cases what people want is the most readable and understandable way to implement a solution.
I quite like the following. Where we first bracket each item in the array with map and then join the items with no delimiter:
const data = ['abc', 'yte', 'juu'];
let brackets = data.map(x => "(" + x + ")");
let result = brackets.join("")
console.log(result);
That of course takes two passes over the array. If you really must have the fastest solution just use a for loop:
const data = ['abc', 'yte', 'juu'];
let result = "";
for (let item of data) {
result += "(" + item + ")";
}
console.log(result);
In order to reduce an array to a single value (be that an object, array, string, number, ...) Javascript has the Array.prototype.reduce method, which achieves the desired result in a single loop and line:
console.log(['abc', 'yte', 'juu'].reduce((a,v)=>`${a}(${v})`,''))
const list = ['abc', 'yte', 'juu'];
const result = list.map(value => `(${value})`).join("");
console.log(result);

Jquery check if one array contains same value

I have an simple javascript array that may contain duplicates or maynot contain duplicates.
var names = [
['aaa','pin/test1.html'],
['bbb','pin/test2.html'],
['ttt','test.html'],
['ggg','test.html'],
['yyy','un/777.html'],
['ggg','test3.html'],
['nnn','test3.html'],
['eee','n/777.html'],
['sss','pin/test1.html'],
['xxx','pin/test2.html'],
['ppp','pin/test1.html'],
];
I need to find the duplicate filepath and put their name into new array. If there is no duplicate then assign its name in first and then assign '' after two values. I could point all the codes that I have tried but it doesnt work. I accept jquery solution also. The expected outcome is this.
var outcome = [
[['aaa','sss','ppp'], 'pin/test1.html'],
[['bbb','eee','xxx'], 'pin/test2.html'],
[['ttt','ggg',''], 'test.html'],
[['yyy','',''], 'un/777.html'],
[['ggg','nnn',''], 'test3.html'],
];
What I have tried is this
for (var i = 0; i < arr.length; i++) {
var uniqueNames = [];
$.each(arr[i], function (i, el) {
if ($.inArray(el, uniqueNames) === -1) uniqueNames.push(el);
});
console.log(uniqueNames);
}
You could take a hash table and an array of empty strings and find the next slot for the value.
The array is reduced by taking an object as accumulator and a destructure array as value (the first part of the array) and key (the second part, aka filepath).
Inside of Array#reduce, a property check with the key is made and if undefined, an array with the wanted structure (array with two items, the first is an array with three emty spaces and the key) is being assigned by using a logical nullish assignment ??=.
The next line assigns the value to the next free slot, an item with an empty string.
Finally the accumulator is returned.
To get only an array as result, a conversion of the values of the object takes place.
let names = [['aaa','pin/test1.html'], ['bbb','pin/test2.html'], ['ttt','test.html'], ['ggg','test.html'], ['yyy','un/777.html'], ['ggg','test3.html'], ['nnn','test3.html'], ['eee','n/777.html'], ['sss','pin/test1.html'], ['xxx','pin/test2.html'], ['ppp','pin/test1.html']],
grouped = Object.values(names.reduce((r, [v, k]) => {
r[k] ??= [Array(3).fill(''), k];
r[k][0][r[k][0].indexOf('')] = v;
return r;
}, {}));
console.log(grouped);
.as-console-wrapper { max-height: 100% !important; top: 0; }
const aux = (names) => {
const hash = {};
let max = 0;
names.forEach(ele => {
if (!hash[ele[1]]) hash[ele[1]] = [];
hash[ele[1]].push(ele[0]);
max = Math.max(hash[ele[1]].length, max);
});
return Object.keys(hash).map(ele => [[...hash[ele], ...Array(max -hash[ele].length).fill("")], ele]);
}
var names = [
['aaa','pin/test1.html'],
['bbb','pin/test2.html'],
['ttt','test.html'],
['ggg','test.html'],
['yyy','un/777.html'],
['ggg','test3.html'],
['nnn','test3.html'],
['eee','n/777.html'],
['sss','pin/test1.html'],
['xxx','pin/test2.html'],
['ppp','pin/test1.html'],
];
console.log(aux(names))
This might help
You do not need jQuery for dealing with regular JS structure, you can achieve what you want with a simple code like this:
var names = [['aaa','pin/test1.html'],['bbb','pin/test2.html'],['ttt','test.html'],['ggg','test.html'],['yyy','un/777.html'],['ggg','test3.html'],['nnn','test3.html'],['eee','n/777.html'],['sss','pin/test1.html'],['xxx','pin/test2.html'],['ppp','pin/test1.html'],];
let lengthToFill = 0;
// collecting all the duplicates into a map
const pathMap = {};
names.forEach(name => {
// just in case if you're not familiar with array destructuring
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment
const [pathName, path] = name;
// make sure we have an array to deal with
// just in case you're not familiar with Nullish coalescing operator (??)
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Nullish_coalescing_operator
pathMap[path] = pathMap[path] ?? [];
pathMap[path].push(pathName);
// tracking the max number of elements we're adding into a single entry
lengthToFill = Math.max(lengthToFill, pathMap[path].length);
});
const result = Object.entries(pathMap).map(entry => {
// constructing new array entry based on the data we've collected so far
return [
entry[1].concat(Array(lengthToFill - entry[1].length).fill('')),
entry[0],
];
});
console.log(result);
This solution will work for any number of elements that you'd like to fill the array with ''. It makes sure that the length of final listing is the same for all entries.

Original index position after filtering an array

I have an array that is filtered based on what the user types into a search box..
var x = ["Apple","Pear","Pineapple"];
var value = e.target.value;
var regex = new RegExp(`^${value}`, 'i');
var filtered = x.sort().filter(v => regex.test(v));
If I were to type "P" into the search box the console would print
["Pear","Pineapple"]
What I need however is another array of the original index position of Pear and Pineapple that would print the following
[1,2]
How would I go about achieving this?
You can do that in a single shot using reduce (read more about reduce here).
There is no need to filter, you can just generate another array, keep track of the index of the currently looped item (assuming you want the sorted index).
If you don't want the sorted index, just remove .sort. Not sure why it's there in the first place.
This solution requires a single iteration, which should be optimal (as long as you remove the unneeded sort).
var x = ["Apple","Pear","Pineapple"];
var value = 'P';
var regex = new RegExp(`^${value}`, 'i');
var filtered = x.sort().reduce((acc, next, i) => { // acc is the current accumulator (initially an empty array), next is looped item, i is item's index (what you want in the result).
return regex.test(next) && acc.push(i), acc // <-- if the regex test is successfull, `i` is pushed to the accumulator. In both cases (so, even if the regex fails) the accumulator is returned for the next iteration.
}, []); // <-- [] is the initial value of `acc`, which is a new empty array.
console.log(filtered);
Instead of filtering the array, filter the keys of the array instead:
var x = ["Apple","Pear","Pineapple"],
value ="P",
regex = new RegExp(`^${value}`, 'i'),
filtered = [...x.keys()].filter(i => regex.test(x[i]));
console.log(filtered)
keys() method returns a Array Iterator. So, you need to use spread syntax or Array.from() to convert it to an array
You could get first the value/index pairs, filter and get either the values or indices.
Intead of a RegExp, you could use String#startsWith, which has no problems of characters with special meanings.
var array = ["Apple", "Pear", "Pineapple"],
value = 'P',
filtered = array
.sort()
.map((v, i) => [v, i])
.filter(([v]) => v.startsWith(value)),
values = filtered.map(([v]) => v),
indices = filtered.map(([, i]) => i);
console.log(values);
console.log(indices);
You can get your indexes with indexOf() from the original array like so:
const x = ["Apple","Pear","Pineapple"];
var regex = new RegExp(`^P`, 'i');
const filtered = x.sort().filter(v => regex.test(v));
const filteredIndexes = filtered.map(v => x.indexOf(v));
console.log(filtered);
console.log(filteredIndexes);
You could also use reduce to do it all in one iteration like the so:
const x = ["Apple","Pear","Pineapple"];
var regex = new RegExp(`^P`, 'i');
const [filtered, filteredIndexes] = x.sort().reduce((acc, val, i) => {
// If the regex fits, add to the arrays
if(regex.test(val)) {
// Adding to the array via array spread operator
acc = [[...acc[0], val],[...acc[1], i]];
}
return acc;
}, [[],[]]); // Initial value of accumulator
console.log(filtered);
console.log(filteredIndexes);

How to get the matching second array of object in es6

I have two array of objects: - better solution
array1= [{id:1,name:"samsung"},{id:2,name:"nokia"},{id:3,name:"Lg"}];
array2 = [{id:5,name:"samsung"},{id:2,name:"panasonics"},{id:7,name:"Lg"}];
Expected output be:
if first array and second array id matches means take the second array name
in above example id 2 matches and we need id:2,name: panasonics.
o/p:
[{id:1,name:"samsung"},{id:2,name:"panasonics"},{id:3,name:"Lg"},{id:5,name:"samsung"},{id:7,name:"Apple"}]
Combine the arrays using Array.concat(), reduce them into a Map by id, and then convert the Map's values to an array with Array.from():
const unionBy = (field, ...arrays) => Array.from(
[].concat(...arrays)
.reduce((r, o) => r.set(o.id, o), new Map)
.values()
);
const array1 = [{id:1,name:"samsung"},{id:2,name:"nokia"},{id:3,name:"Lg"}];
const array2 = [{id:5,name:"samsung"},{id:2,name:"panasonics"},{id:7,name:"Lg"}];
const result = unionBy('id', array1, array2);
console.log(result);
You can use a simple .forEach() loop like below (you can also use a for loop if you want, but .forEach() is easier).
This code loops through array1, and loops through array2 in that loop. It then checks if the ids are the same. If there are, the name is appended to result.
const array1= [{id:1,name:"samsung"},{id:2,name:"nokia"},{id:3,name:"Lg"}];
const array2 = [{id:5,name:"samsung"},{id:2,name:"panasonics"},{id:7,name:"Lg"}];
let result = [];
array1.forEach(e1 => {
array2.forEach(e2 => {
if (e1.id == e2.id) {
result.push(e2.name);
}
});
});
console.log(result);
Use map() and concat() like the following code
array1= [{id:1,name:"samsung"},{id:2,name:"nokia"},{id:3,name:"Lg"}];
array2 = [{id:5,name:"samsung"}, {id:2,name:"panasonics"},{id:7,name:"Lg"}];
var array3=array1.map(function(i,v){
if(array2[v].id==i.id){
return array2[v]
}
else return i
})
array4=array3.concat(array2);
console.log(array4);

JS array index number into value with string replace

I have a multidimentional array:
(3) [Array(1), Array(1), Array(1)]
0:["('idDocDetail','0','$createdBy')"]
1:["('idDocDetail','2','$createdBy'),('idDocDetail','4','$createdBy')"]
2:["('idDocDetail','0','$createdBy')"]
I need to replace the string value idDocDetail with the index number, like this.
(3) [Array(1), Array(1), Array(1)]
0:["('0','0','$createdBy')"]
1:["('1','2','$createdBy'),('1','4','$createdBy')"]
2:["('2','0','$createdBy')"]
I'm trying to use replace, but I got the replace is not a function error.
array.forEach(function(item, index) {
return item.toString().replace('idDocDetail', index);
});
what am I doing wrong? Replace is the right way to do this?
I do recommend you to learn to perform changes in immutable manner. This is where Array.prototype.map plays well
const data = [
["('idDocDetail','0','$createdBy')"],
["('idDocDetail','2','$createdBy'),('idDocDetail','4','$createdBy')"],
["('idDocDetail','0','$createdBy')"]
]
const modified = data.map((item, index) =>
item.map(str => str.replace(/idDocDetail/g, index ))
)
modified.forEach(x => console.log(JSON.stringify(x)))
Here, this works for your code structure. It uses map() to produce a new array by just replacing the string of interest with the index.
EDIT: Added a nested map for clarity + regular expression to find all instances of 'idDocDetail' in the string, not just the first one. replace method when given a raw string value only handles the first instance of a string occurring.
const array = [["('idDocDetail','0','$createdBy')"],
["('idDocDetail','2','$createdBy'),('idDocDetail','4','$createdBy')"],
["('idDocDetail','0','$createdBy')"]]
var find = 'idDocDetail';
var re = new RegExp(find, 'g');
let newArray = array.map((val, i) => val.map(string => {
return string.replace(re, i)
}))
console.log(newArray)
You can loop over your array and edit it.
let array = [
["('idDocDetail','0','$createdBy')"],
["('idDocDetail','2','$createdBy'),('idDocDetail','4','$createdBy')"],
["('idDocDetail','0','$createdBy')"],
];
array.forEach((e, i) => {
array[i] = [e[0].replace(/idDocDetail/g, i)];
});
console.log(array);
You can not replace an item by calling a method on the item being replaced. Instead you need to call it on the array. You can do it this way:
for (var i=0; i<array.length; i++) {
array[i][0] = i;
}
forEach ignores the return of the callback. You need to assign to the original array at the current index.
var array = [
["('idDocDetail','0','$createdBy')"],
["('idDocDetail','2','$createdBy'),('idDocDetail','4','$createdBy')"],
["('idDocDetail','0','$createdBy')"]
];
array.forEach(function(item, index) {
array[index] = item.map(s => s.replace('idDocDetail', index));
});
console.log(array);

Categories