create one array after using map() twice - javascript

I may or may not get in 2 differently formatted bits of data.
They both need to be stripped of characters in different ways. Please excuse the variable names, I will make them better once I have this working.
const cut = flatten.map(obj => {
return obj.file.replace("0:/", "");
});
const removeDots = flatten.map(obj => {
return obj.file.replace("../../uploads/", "");
})
I then need to push the arrays into my mongo database.
let data;
for (const loop of cut) {
data = { name: loop };
product.images.push(data);
}
let moreData;
for (const looptwo of removeDots) {
moreData = {name: looptwo};
product.images.push(moreData);
}
I wanted to know if there is a way to either join them or do an if/else because the result of this is that if I have 2 records, it ends up duplicating and I get 4 records instead of 2. Also, 2 of the records are incorrectly formatted ie: the "0:/ is still present instead of being stripped away.
Ideally I would like have a check that if 0:/ is present, remove it, if ../../uploads/ is present or if both are present, remove both. And then create an array from that to push.

You can do your 2 replace on the same map :
const processed = flatten.map(obj => {
return obj.file.replace("0:/", "").replace("../../uploads/", "");
});

Since you know the possible patterns, you can create a regex and use it to replace any occurrences.
const regex = /(0:\/|(\.\.\/)+uploads\/)/g
const processed = flatten.map(obj => obj.file.replace(regex, ''));
You can verify here
Note, regex is a pattern based approach. So it has pros and cons.
Pro:
You can have any number of folder nesting. Using string ../../uploads/ will restrict you with 2 folder structure only.
You can achieve transformation in 1 operation and code looks clean.
Cons:
Regex can be hard to understand and can reduce readability of code a bit. (Opinionated)
If you have pattern like .../../uploads/bla, this will be parsed to .bla.

Since you ask also about a possible way of joining two arrays, I'll give you couple of solutions (with and w/o joining).
You can either chain .replace on the elements of the array, or you can concat the two arrays in your solution. So, either:
const filtered = flatten.map(obj => {
return obj.file.replace('0:/', '').replace('../../uploads/', '');
});
Or (joining the arrays):
// your two .map calls go here
const joinedArray = cut.concat(removeDots);

Related

How to NOT select this but anything else in Regexr?

I have this string made up for a TMS program... I later found out I want the program to NOT select these postalcodes, it's now matching the string. I want it to be able to select anything between 1000-10000\s*a-zA-Z except for this:
(8388|8389|8390|8391|8392|8393|8394|8395|8396|8397|8398|8400|8401|8403|8404|8405|8406|8407|8408|8409|8410|8411|8412|8413|8414|8415|8420|8421|8422|8423|8424|8425|8426|8427|8428|8430|8431|8432|8433|8434|8435|8440|8441|8442|8443|8444|8445|8446|8447|8448|8449|8451|8452|8453|8454|8455|8456|8457|8458|8459|8461|8462|8463|8464|8465|8466|8467|8468|8469|8470|8471|8472|8474|8475|8476|8477|8478|8479|8481|8482|8483|8484|8485|8486|8487|8488|8489|8490|8491|8493|8494|8495|8497|8500|8501|8502|8503|8505|8506|8507|8508|8511|8512|8513|8514|8515|8516|8517|8520|8521|8522|8523|8524|8525|8526|8527|8528|8529|8530|8531|8532|8534|8535|8536|8537|8538|8539|8541|8542|8550|8551|8552|8553|8554|8556|8560|8561|8563|8564|8565|8566|8567|8571|8572|8573|8574|8581|8582|8583|8584|8600|8601|8602|8603|8604|8605|8606|8607|8608|8611|8612|8613|8614|8615|8616|8617|8618|8620|8621|8622|8623|8624|8625|8626|8627|8628|8629|8631|8632|8633|8635|8636|8637|8641|8642|8644|8647|8650|8651|8658|8700|8701|8702|8710|8711|8713|8715|8721|8722|8723|8724|8730|8731|8732|8733|8734|8735|8736|8737|8741|8742|8743|8744|8745|8746|8747|8748|8749|8751|8752|8753|8754|8755|8756|8757|8758|8759|8761|8762|8763|8764|8765|8766|8771|8772|8773|8774|8775|8800|8801|8802|8804|8805|8806|8807|8808|8809|8811|8812|8813|8814|8816|8821|8822|8823|8830|8831|8832|8833|8834|8835|8841|8842|8843|8844|8845|8850|8851|8852|8853|8854|8855|8856|8857|8860|8861|8862|8871|8872|8880|8881|8882|8883|8884|8885|8890|8891|8892|8893|8894|8895|8896|8897|8899|8900|8901|8902|8903|8911|8912|8913|8914|8915|8916|8917|8918|8919|8921|8922|8923|8924|8925|8926|8927|8931|8932|8933|8934|8935|8936|8937|8938|8939|8941|9001|9003|9004|9005|9006|9007|9008|9009|9011|9012|9013|9014|9021|9022|9023|9024|9025|9026|9027|9031|9032|9033|9034|9035|9036|9037|9038|9040|9041|9043|9044|9045|9047|9050|9051|9053|9054|9055|9056|9057|9060|9061|9062|9063|9064|9067|9071|9072|9073|9074|9075|9076|9077|9078|9079|9081|9082|9083|9084|9086|9087|9088|9089|9091|9100|9101|9102|9103|9104|9105|9106|9107|9108|9109|9111|9112|9113|9114|9121|9122|9123|9124|9125|9131|9132|9133|9134|9135|9136|9137|9138|9141|9142|91439144|9145|9146|9147|9148|9150|9151|9152|9153|9154|9155|9156|9160|9161|9162|9163|9164|9166|9171|9172|9173|9174|9175|9176|9177|9178|9200|9201|9202|9203|9204|9205|9206|9207|9211|9212|9213|9214|9215|9216|9217|9218|9219|9221|9222|9223|9230|9231|9233|9240|9241|9243|9244|9245|9246|9247|9248|9249|9250|9251|9254|9255|9256|9257|9258|9260|9261|9262|9263|9264|9265|9269|9270|9271|9280|9281|9283|9284|9285|9286|9287|9288|9289|9290|9291|9292|9293|9294|9295|9296|9297|9298|9299|9851|9852|9853|9871|9872|9873|9950)\s*[a-zA-Z]{2}
I obviously tried the [^] function and the ?: function but I can't get it working properly.
Just break this string into a set(I think slice function can do that) then sort it and every time you get a value match if it exists in this set or not.
Lets make it easier, I am guessing you are getting numbers in string format of some sort with some form of separation in this case "|".
Step one create array by splinting string based on separator
Step two use filter function that will return a new array based on conditions you provide as shown in example.
Below example takes into consideration edge cases e.g. we are only comparing numbers alphabets are of lesser comparative value to us. What we have to make sure is any comparative value starts with number rest is is all gibberish. So extract number and run bit of magic on that.
Your sting was too long I have used a hypothetical scenario to give you what you want. Rest should be self explanatory in example.
data = '100|999|1000|s1000|10d00|1000f|2500|7500|10000|10001|10500';
dataArray = data.split("|");
dataFiltered = dataArray.filter(function (item) {
extractedNumber = item.match(/^\d+/g);
if(extractedNumber > 999 && extractedNumber <10001) {
return item;
}})
console.log(dataFiltered)
to check on whats being extracted run following and update function as needed.
data = '100|999|1000|s1000|10d00|1000f|2500|7500|10000|10001|10500';
dataArray = data.split("|");
dataFiltered = dataArray.filter(function (item) {
extractedNumber = item.match(/^\d+/);
console.log(extractedNumber);
if(extractedNumber > 999 && extractedNumber <10001) {
return item;
}})
console.log(dataFiltered)

URL Parse Exercise (JavaScript)

So here is a description of the problem that I've been talked to solve:
We need some logic that extracts the variable parts of a url into a hash. The keys
of the extract hash will be the "names" of the variable parts of a url, and the
values of the hash will be the values. We will be supplied with:
A url format string, which describes the format of a url. A url format string
can contain constant parts and variable parts, in any order, where "parts"
of a url are separated with "/". All variable parts begin with a colon. Here is
an example of such a url format string:
'/:version/api/:collection/:id'
A particular url instance that is guaranteed to have the format given by
the url format string. It may also contain url parameters. For example,
given the example url format string above, the url instance might be:
'/6/api/listings/3?sort=desc&limit=10'
Given this example url format string and url instance, the hash we want that
maps all the variable parts of the url instance to their values would look like this:
{
version: 6,
collection: 'listings',
id: 3,
sort: 'desc',
limit: 10
}
So I technically have a semi-working solution to this but, my questions are:
Am I understanding the task correctly? I'm not sure if I'm supposed to be dealing with two inputs (URL format string and URL instance) or if I'm just supposed to be working with one URL as a whole. (my solution takes two separate inputs)
In my solution, I keep reusing the split() method to chunk the array/s down and it feels a little repetitive. Is there a better way to do this?
If anyone can help me understand this challenge better and/or help me clean up my solution, it would be greatly appreciated!
Here is my JS:
const obj = {};
function parseUrl(str1, str2) {
const keyArr = [];
const valArr = [];
const splitStr1 = str1.split("/");
const splitStr2 = str2.split("?");
let val1 = splitStr2[0].split("/");
let val2 = splitStr2[1].split("&");
splitStr1.forEach((i) => {
keyArr.push(i);
});
val1.forEach((i) => {
valArr.push(i);
});
val2.forEach((i) => {
keyArr.push(i.split("=")[0]);
valArr.push(i.split("=")[1]);
});
for (let i = 0; i < keyArr.length; i++) {
if (keyArr[i] !== "" && valArr[i] !== "") {
obj[keyArr[i]] = valArr[i];
}
}
return obj;
};
console.log(parseUrl('/:version/api/:collection/:id', '/6/api/listings/3?sort=desc&limit=10'));
And here is a link to my codepen so you can see my output in the console:
https://codepen.io/TOOTCODER/pen/yLabpBo?editors=0012
Am I understanding the task correctly? I'm not sure if I'm supposed to
be dealing with two inputs (URL format string and URL instance) or if
I'm just supposed to be working with one URL as a whole. (my solution
takes two separate inputs)
Yes, your understanding of the problem seems correct to me. What this task seems to be asking you to do is implement a route parameter and a query string parser. These often come up when you want to extract data from part of the URL on the server-side (although you don't usually need to implement this logic your self). Do keep in mind though, you only want to get the path parameters if they have a : in front of them (currently you're retrieving all values for all), not all parameters (eg: api in your answer should be excluded from the object (ie: hash)).
In my solution, I keep reusing the split() method to chunk the array/s
down and it feels a little repetitive. Is there a better way to do
this?
The number of .split() methods that you have may seem like a lot, but each of them is serving its own purpose of extracting the data required. You can, however, change your code to make use of other array methods such as .map(), .filter() etc. to cut your code down a little. The below code also considers the case when no query string (ie: ?key=value) is provided:
function parseQuery(queryString) {
return queryString.split("&").map(qParam => qParam.split("="));
}
function parseUrl(str1, str2) {
const keys = str1.split("/")
.map((key, idx) => [key.replace(":", ""), idx, key.charAt(0) === ":"])
.filter(([,,keep]) => keep);
const [path, query = ""] = str2.split("?");
const pathParts = path.split("/");
const entries = keys.map(([key, idx]) => [key, pathParts[idx]]);
return Object.fromEntries(query ? [...entries, ...parseQuery(query)] : entries);
}
console.log(parseUrl('/:version/api/:collection/:id', '/6/api/listings/3?sort=desc&limit=10'));
It would be even better if you don't have to re-invent the wheel, and instead make use of the URL constructor, which will allow you to extract the required information from your URLs more easily, such as the search parameters, this, however, requires that both strings are valid URLs:
function parseUrl(str1, str2) {
const {pathname, searchParams} = new URL(str2);
const keys = new URL(str1).pathname.split("/")
.map((key, idx) => [key.replace(":", ""), idx, key.startsWith(":")])
.filter(([,,keep]) => keep);
const pathParts = pathname.split("/");
const entries = keys.map(([key, idx]) => [key, pathParts[idx]]);
return Object.fromEntries([...entries, ...searchParams]);
}
console.log(parseUrl('https://www.example.com/:version/api/:collection/:id', 'https://www.example.com/6/api/listings/3?sort=desc&limit=10'));
Above, we still need to write our own custom logic to obtain the URL parameters, however, we don't need to write any logic to extract the query string data as this is done for us by using URLSearchParams. We're also able to lower the number of .split()s used as we can obtain use the URL constructor to give us an object with a parsed URL already. If you end up using a library (such as express), you will get the above functionality out-of-the-box.

Why this includes() case return false?

var product_id = "14728";
console.log(product_id.includes("14782,12434,3143")); // this return false
Example.
I just want to check that my product_id is within those other articles ids string
Two reasons:
You have it backwards. You are asking if "14728" includes "14782,12434,3143" (which it doesn't, the latter is too long to be included in the former for a start), not the other way around
"14782,12434,3143" doesn't include "14728" anyway
Your approach is also broken. "14782,12434,3143" includes "314". Presumably you want to only match complete numbers in the comma-separated list. You need to use Array.prototype.includes, not String.prototype.includes.
const myData = ["14782", "12434", "3143"];
const mySearch = "14728"; // Not in the array
const myOtherSearch = "12434"; // In the array
console.log(myData.includes(mySearch));
console.log(myData.includes(myOtherSearch));

Manipulate urls with regular expressions instead of the slip approach

Basically I have an url which looks like this structurally speaking:
http://www.my-site.com/topic1/topic2/topic3/topic4/topic5
and I want to do 2 things to it:
1. check the structure and validate it
2. replace both topic3 and topic4 with a new parameters called topic6
This is my solution for now but I am interested to build something more optimize.
if ((url.match(/\//g) || []).length === 7) {
const arr = url.split('/');
const topic5 = arr.pop();
arr.pop();
arr.pop();
arr.push('topic6', topic5);
return arr.join('/');
}
So as you can see, for the fact that I am not very good at regular expressions I have used another approach which doesn't look that good. I basically check for the number of / in the string, if tey are 7 it means that the structure of the url is good and that on this type of url I should apply the next steps. After that I grab the last param of the url and also remove it and next after that I remove the last 2 parameters and add the new one instead along with the topic5.
In case you you have a better approach, please let me know. I think that it can be done by writing less number of lines of code but as I said, I am not very familiar with regular expressions.
One way is to use replace to match last 3 with /, capture only the last / part in capture group and replace with the topics6 and value of captured group
let url = "http://www.my-site.com/topic1/topic2/topic3/topic4/topic5"
let func = (url) => {
if ((url.match(/\//g) || []).length === 7) {
const arr = url.replace(/(?:\/[^\/]+){2}(\/[^\/]+)$/, (m, g) => `\/topics6${g}`)
return arr
}
return url
}
console.log(func(url))

Pick out words in a string that are in array

I have spent hours, close to 8 hours none stop on this, I am trying to use jQuery/JS to create two arrays, one which is dynamic as it is loading a chat script and will be split by whitespace in to an array, for example:
String: Hello my name is Peter
Converted to (message) array: ['hello','my','name','is','peter'];
I have a set array to look out for specific words, in this example let us use:
(find array) ['hello','peter'] however, this array is going to contain up to 20 elements and I need to ensure it searches the message array efficiently, please help.
I can help you with that.
var arrayOfWords = $(".echat-shared-chat-message-body").last().text().split(" ");
That code is actually working! i went to an open chat in this website so I can tested.
So just replace the word REPLACE with your DOM object :)
var arrayOfWords = $("REPLACE").last().text().split(" ");
If I understood well, you're asking to filter an array of string (from an incoming string) given a second array.
In your described case you'll certainly not have to worry about efficiency, really. Unless your incoming message is allowed to be very very big.
Given that, there is a dozen of options, I think this is the most succinct:
const whitelist = [
'hello',
'peter'
]
const message = 'hello my name is Peter'.split(' ')
const found = message.filter(function(word) {
return whitelist.indexOf(word) > -1
}
You can treat invariant case:
const whitelistLower = whitelist.toLowerCase()
const foundInvariantCase = message.filter(function(word) {
return whitelist.indexOf(word.toLowerCase()) > -1
}
Or use ESS Set:
const whitelistSet = new Set(whitelist)
const found = message.filter(function(word) {
return whitelistSet.has(word)
}

Categories