If I have this very simple array:
let result = ["doc1.rtf","doc2.rtf","test/doc4.rtf","test/doc4.rtf","test/doc6.rtf"]
I could find the unique occurrences by running something like.
let unique = [...new Set(result)];
Which will return me:
["doc1.rtf","doc2.rtf","test/doc4.rtf","test/doc6.rtf"]
But what I want to do is search the array for anything unique after filtering out the contents of anything up to a leading slash. So the array will look like this below before I filter out the duplicate test/
let filtered = ["doc1.rtf","doc2.rtf","test/","test/","test/"]
Thanks in advance. Is there a way to do above in one operation?
I hope I understand the question correctly, but you can play around with map. For example:
result.map(r => r.split('/')[0])
# ["doc1.rtf", "doc2.rtf", "test", "test", "test"]
result.map(r => r.replace(/\/.*/, '/'))
# ["doc1.rtf", "doc2.rtf", "test/", "test/", "test/"]
might yield what you're looking for.
To remove anything up to a leading slash you could use map with split:
let result = ["doc1.rtf","doc2.rtf","test/doc4.rtf","test/doc4.rtf","test/doc6.rtf"];
result.map(i => i.split('/')[0]);
// ["doc1.rtf", "doc2.rtf", "test", "test", "test"]
And than look for unique elements
let unique = [...new Set(result)];
//["doc1.rtf", "doc2.rtf", "test"]
You could accomplish the filtration in one pass by mapping each item of the array to a resolver, then using a Set for membership.
const uniqMap = resolver => function uniqMapping(array) {
const existing = new Set(),
result = []
for (let i = 0; i < array.length; i++) {
const item = array[i]
const resolvedItem = resolver(item)
if (existing.has(resolvedItem)) {
continue
}
existing.add(resolvedItem)
result.push(resolvedItem)
}
return result
}
let data = ["doc1.rtf","doc2.rtf","test/doc4.rtf","test/doc4.rtf","test/doc6.rtf"]
console.log(
uniqMap(item => item.split('/')[0])(data),
) // [ 'doc1.rtf', 'doc2.rtf', 'test' ]
Related
I want to remove those items from arr_2 which contains the domain name from arr_1
let arr_1 = ["domain1.com", "domain2.com"];
let arr_2 = [
"domain1.com/about-us",
"domain3.com/contact-us",
"domain4.com/privacy-policy",
"domain2.com/pricing-plans",
"sub.domain2.com/home-1",
];
let filtered_arr = [];
arr_2.forEach((item) => {
if (item.indexOf(arr_1) == -1) {
filtered_arr.push(item);
}
});
console.log(filtered_arr);
i want the result ["domain3.com/contact-us", "domain4.com/privacy-policy"] from this code, but it prints the whole arr_2
You can't call indexOf on a string and pass an array as an argument.
You should use find to check if item has a domain from arr_1.
And it's a lot cleaner code using filter than forEach.
let arr_1 = ["domain1.com", "domain2.com"];
let arr_2 = [
"domain1.com/about-us",
"domain3.com/contact-us",
"domain4.com/privacy-policy",
"domain2.com/pricing-plans",
"sub.domain2.com/home-1",
];
let filtered_arr = arr_2.filter(item => {
return !arr_1.find(domain => item.includes(domain));
});
console.log(filtered_arr);
Note: This would also filter out "example.com/domain1.com".
Your code right now is returning the whole arr_2 because your filtering logic does not check if each item of arr_2 contains one of the matching strings in arr_1.
indexOf(arr_1) is essentially searching each item in arr_2 for the entire arr_1 array. The function will always return -1 because each item of arr_2 is a string and will never match with the entire arr_1 array.
I assume you'd want to go through each item in arr_1 as well, so you should probably do arr_1.forEach((item1) => { }) inside the forEach loop for arr_2, and do the indexOf check inside this inner loop.
you can achive it using filter some and includes
let arr_1 = ["domain1.com", "domain2.com"];
let arr_2 = [
"domain1.com/about-us",
"domain3.com/contact-us",
"domain4.com/privacy-policy",
"domain2.com/pricing-plans",
"sub.domain2.com/home-1",
];
const arr3 = arr_2.filter(url => !arr_1.some(domain => url.includes(domain)))
console.log(arr3)
Someone asked me to solve this problem: Return only those objects whose property "enrollmentId" is in another number array: So I came up with this, and it works, however, I'm using a for inside a for, and I was wondering what's the best approach to this kind of problem. Please, check it out
const companions = [
{name:"camila", enrollmentId:1},
{name:"oscar", enrollmentId:2},
{name:"rupertina", enrollmentId:3}
];
const participants = [7,2,4]
const finalResult = [];
for(i=0; i< companions.length; i++){
let alumno = companions[i];
for(j=0; j< participants.length; j++){
let participante = participants[j];
if(alumno.enrollmentId == participante){
finalResult.push(alumno);
}
}
}
console.log(finalResult)
Filter the original array by whether the enrollmentId of the object being iterated over is included in the participants.
const companions = [
{name:"camila", enrollmentId:1},
{name:"oscar", enrollmentId:2},
{name:"rupertina", enrollmentId:3}
];
const participants = [7, 2, 4]
const finalResult = companions.filter(obj => participants.includes(obj.enrollmentId));
console.log(finalResult)
I would use Array.filter to omit invalid rows, and Array.includes for the validity test
const companions = [
{name:"camila", enrollmentId:1},
{name:"oscar", enrollmentId:2},
{name:"rupertina", enrollmentId:3}
];
const participants = [7,2,4];
const finalResult = companions.filter(companion => {
return participants.includes(companion.enrollmentId);
});
console.log(finalResult);
If you want the ES6 way, go with code_monk code BUT imma up code_monk code, will all do respect (I cannot add a comment to his code as I am new to stack overflow and do not have enough reputation.) BUT an arrow function ( => ) does not need the keyword return nor the function budy {}, because it is implicit that a value will be returned after the =>
const companions = [
{name:"camila", enrollmentId:1},
{name:"oscar", enrollmentId:2},
{name:"rupertina", enrollmentId:3}
];
const participants = [7,2,4];
const finalResult = companions.filter(companion => participants.includes(companion.enrollmentId));
console.log(finalResult);
good morning I have these text strings:
json_schema.account_overview.name
json_schema.no_owned.contact.contact
but now I'm trying to separate according to the string 'json_schema.no_owned', doing like this:
my_string.split ("json_schema.no_owned."). filter (x => x);
but doing a console.log of that result I get this
the first arrangement is fine, since to that same arrangement I can apply another split and I will have again separated by '.'
but the second fix has nothing to do with what I was saying should be after 'json_schema.no_owned.' (note the period at the end)
This way I am trying to do it:
let string ="json_schema.no_owned.contact.contact";
let arrayString = [
'json_schema.no_owned.contact.contact',
'json_schema.account_overview.name'
];
let schema = "";
for(let i in arrayString){
schema = arrayString[i].split("json_schema.no_owned.").filter(x => x);
console.log(schema);
}
I only want to have in an array the elements that are after 'json_schema.no_owned'
Thanks.
You can check if element has "json_schema.no_owned." part at all:
let string ="json_schema.no_owned.contact.contact";
let arrayString = [
'json_schema.no_owned.contact.contact',
'json_schema.account_overview.name'
];
let schema = "";
for(let i in arrayString){
if (arrayString[i].includes("json_schema.no_owned.")) {
schema = arrayString[i].split("json_schema.no_owned.").filter(x => x);
console.log(schema);
}
}
Maybe you can use a short way to do it.
let arrayString = [
'json_schema.no_owned.contact.contact',
'json_schema.account_overview.name'
];
const schemas = arrayString.filter(x => x.includes("json_schema.no_owned."))
.map(x => x.split("json_schema.no_owned.")[1]);
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);
If I have two arrays with files
arr1 = ['file1.webp', 'file2.webp', ...];
arr2 = ['file1.jpg', 'file2.png', 'file3.jpg', 'file4.jpg', ...];
how would I check which array items are equal, minus the *.format part?
The idea is that, if there are two equal items, a webp and an alternative source are available. While if an item has no match, no webp source was provided. Both cases would lead to different image handling later on.
I could compare the items inside two arrays like so: let match = arr1.find( val => arr2.includes(val) );
But this compares each entire item. I only want to compare the file names. The formats in which the files were provided need to be cut off, so I get:
arr1 = ['file1', 'file2', ...];
arr2 = ['file1', 'file2', 'file3', 'file4', ...];
I can then filter out all matches between the two arrays. I've been searching for a solution for a real while, but I'm still not sure how to get there.
With a function that trims off the file extension, you can construct a Set of one of the transformed arrays. Then iterate over the other array and check whether its transformed item is in the Set or not:
const arr1 = ['file1.webp', 'file2.webp'];
const arr2 = ['file1.jpg', 'file2.png', 'file3.jpg', 'file4.jpg'];
const transform = str => str.replace(/\.[^.]+$/, '');
const set1 = new Set(arr1.map(transform));
for (const item of arr2) {
if (set1.has(transform(item))) {
console.log('Match for', item);
} else {
console.log('No match for', item);
}
}
You can use filter() with nested some(). To get the file name from complete name use split('.')and get the first element using .split('.')[0]
let arr1 = ['file1.webp', 'file2.webp'];
let arr2 = ['file1.jpg', 'file2.png', 'file3.jpg', 'file4.jpg'];
let res = arr2.filter(a => arr1.some(b => a.split('.')[0] === b.split('.')[0]));
console.log(res)
You could filter by looking to the right side.
const getName = s => s.replace(/\.[^.]+$/, '');
var array1 = ['file1.webp', 'file2.webp'],
array2 = ['file1.jpg', 'file2.png', 'file3.jpg', 'file4.jpg'],
set1 = new Set(array1.map(getName)),
common = array2.filter(s => set1.has(getName(s)));
console.log(common);
write extract method to get value to compare. Just use the extract method in your code. Alternatively, you can build an arr2Obj to not to repeat the searches.
const arr1 = ["file1.webp", "file2.webp"];
const arr2 = ["file1.jpg", "file2.png", "file3.jpg", "file4.jpg"];
const extract = item => item.split(".")[0];
let match = arr1.find(val => arr2.map(x => extract(x)).includes(extract(val)));
console.log(match);
// Alternatively,
const arr2Obj = Object.assign({}, ...arr2.map(x => ({ [extract(x)]: 1 })));
const match2 = arr1.find(val => extract(val) in arr2Obj);
console.log(match2);