Inserting variables into regular expressions - javascript

I'm trying to write code that will allow user to check to see if I have been to a specific country.
I've tried this by getting input from user via prompt. Taking that input, storing it into a variable and then inserting that variable into a regex. From there, I attempted to use the .some method on my array of countries, utilizing the regex and the user input variable to determine whether or not I have been to the country that the user specifies.
var countries = ['US', 'UK', 'Canda', 'Mexico', 'Panama', 'Dominican
Republic', 'Brazil', 'Germany', 'France', 'Portugal',
'Spain', 'the Netherlands'];
var userCountry = prompt("Please enter a country", "");
var beenToUserCountry = countries.some(country =>
/^userCountry$/i.test(country));
if (beenToUserCountry) {
document.write(`Yes, I have been to ${userCountry}.`);
} else {
document.write(`No, I haven't been to ${userCountry} yet.`);
}
I expect that the code will print "Yes..." for countries that a part of my countries array and and "No..." for ones that are not. Instead, each country that I insert into the prompt gets me a "No..." Help!

You can use a RegExp object for that, here is an example:
var countries = ['US', 'UK', 'Canda', 'Mexico', 'Panama', 'Dominican Republic', 'Brazil', 'Germany', 'France', 'Portugal',
'Spain', 'the Netherlands'];
var userCountry = prompt("Please enter a country", "");
var beenToUserCountry = countries.some(country =>
new RegExp(`^${userCountry}$`, "i").test(country));
if (beenToUserCountry) {
document.write(`Yes, I have been to ${userCountry}.`);
} else {
document.write(`No, I haven't been to ${userCountry} yet.`);
}
As #Bergi has mentioned, you should probably escape userCountry to remove any special characters from it, you can find a good example of how you can do that here

Related

Displaying conditional excel data based on userInput React

I have an excel file (is quite large) as follows:
Region Country City
North America United States Kentucky
North America United States New York
... All cities in US
North America Canada Alberta
... All cities in Canada
Europe France Nice
... All cities in France
I basically want to convert this to a front-end form. So I would have 3 inputs (one for region, one for country, and one for city). Now, I would like a way where if a user selects North America as a region, I only allow them to select countries within North America, and when a user selects a country, only show them cities within a country.
My current approach to tackle countries within a region is quite simple since there are not many regions:
Main Function - content
function content(){
const [regionValue, setRegionValue] = React.useState();
const [countryValue, setCountryValue] = React.useState();
const [cityValue, setCityValue] = React.useState();
...Render components
<RegionSelect regionValue={regionValue} setRegionValue={setRegionValue}></RegionSelect>
<CountrySelect countryValue={countryValue} setCountryValue={setCountryValue} regionValue={regionValue}></CountrySelect>
}
Function for Region:
export const REGIONS = [
{ label: 'North America', value: 'North America' },
{ label: 'South America', value: 'South America' },
{ label: 'Europe', value: 'Europe' }
...
];
function RegionSelect(props){
return (
<Select options = {REGIONS} value = props.regionValue onChange = props.setRegionValue /> //My custom component which just allows user to select and changes the value accordingly
)
}
Function for Country:
const NA_COUNTRIES = [
{ label: 'Canada', value: 'Canada' },
{ label: 'United States', value: 'United States' },
{ label: 'Mexico', value: 'Mexico' }
]
const SA_COUNTRIES =....
function CountrySelect(props){
//since I passed in region to props, I can do an if condition to fill select statement with refined options:
if (props.regionValue == 'North America'){
<Select options = {NA_COUNTRIES} value = props.countryValue onChange = props.setCountryValue />
}
else if..... #Else if statements for every region to display other options
}
Now the countries are quite easy since there aren't many regions but the cities is where it becomes a bit more difficult and tedious. Is it possible for me to do this a better way (maybe by directly reading a csv file in react and doing a match/join)?

How to Filter an array of objects to find the objects that share cross referencing properties

So say for example I'm making a Social app, and I have a user whom I'm trying to make a group match for
const user = {Name: Stan, location: "Chicago", preferences: {locations: ["New York"]} }
and a collection of people objects like so
const matchPool =
[{Name: Bob, location: "New York", preferences: {locations: ["Chicago"]} },
{Name: Susan, location: "Miami", preferences: {locations: ["Chicago", "Miami"]} },
{Name: Tom, location: "Chicago", preferences: {locations: ["Chicago", "New York"]} },
{Name: Sally, location: "New York", preferences: {locations: ["Chicago", "LA"]} },
{Name: Carl, location: "New York", preferences: {locations: ["Detroit", "LA", "Chicago"]} }]
Say I wanted a group with Stan included, How would I go about filtering so that every member of the group has a location that is in the preferences of every other member of the group?
My first thought was to use lodash with a filter like so
const FilteredPeople = _.filter(matchPool, function(matchCandidate) {
return user.preferences.locations.indexOf(matchCandidate.location) != -1 &&
matchCandidate.preferences.locations.indexOf(user.location) != -1
});
If I add Stan to this group returned we would end up with the following
[{Name: Stan, location: "Chicago", preferences: {locations: ["New York"]}}
{Name: Bob, location: "New York", preferences: {locations: ["Chicago"]}},
{Name: Sally, location: "New York", preferences: {locations: ["Chicago", "LA"]}},
{Name: Carl, location: "New York", preferences: {locations: ["Detroit", "LA", "Chicago"]}}]
Notice the issue is that while Stan is an acceptable match for Bob, Sally, and Carl and vice versa, Bob/Sally/Carl are not acceptable matches for each other because none of them have New York as a location preference.
I realize its not possible from this small data set but given I have a large match pool with many people, how would I filter so that ALL people retuned are both compatible with the seed person(Stan) and each other?
Edit: there was some confusion so to say it another way
The location property is where that person is, the preference location array is the cities where that person is willing to meet other people from, so when we form a group all members need to have a location that is in the preference location array of every other member
See if this does it for you... it just keeps track of where each match is from to make sure we can check others against the current group. I changed Sally's preferences to include New York so she's included in the matches
const user = {Name: 'Stan', location: "Chicago", preferences: {locations: ["New York"]} }
const matchPool =
[{Name: 'Bob', location: "New York", preferences: {locations: ["Chicago"]} },
{Name: 'Susan', location: "Miami", preferences: {locations: ["Chicago", "Miami"]} },
{Name: 'Tom', location: "Chicago", preferences: {locations: ["Chicago", "New York"]} },
{Name: 'Sally', location: "New York", preferences: {locations: ["New York","Chicago"]} },
{Name: 'Carl', location: "New York", preferences: {locations: ["Detroit", "LA", "Chicago"]} }]
let matches=[]
let locs = [user.location]
matchPool.forEach(m=>{
//If a user from the pool matches, add them and also keep track of their location to ensure future matches
if (user.preferences.locations.indexOf(m.location)>-1 && locs.every(val => m.preferences.locations.includes(val))){
matches.push(m)
locs.push(m.location)
}
})
console.log(matches)
const matchPool = [
{Name: 'Bob', location: 'New York', preferences: {locations: ['Chicago']}},
{Name: 'Susan', location: 'Miami', preferences: {locations: ['Chicago', 'Miami']}},
{Name: 'Tom', location: 'Chicago', preferences: {locations: ['Chicago', 'New York']}},
{Name: 'Sally', location: 'New York', preferences: {locations: ['Chicago', 'LA']}},
{Name: 'Carl', location: 'New York', preferences: {locations: ['Detroit', 'LA', 'Chicago']}},
];
const target = {Name: 'Stan',location: 'Chicago',preferences: { locations: ['New York']}};
let matchGroup = matchPool.filter((user) => {
if (
// user in group prefers target's location
user.preferences.locations.includes(target.location) &&
// user's location inside targets prefered locations
target.preferences.locations.includes(user.location)
) {
return user;
}
});
matchGroup = [target, ...matchGroup];
console.log(JSON.stringify(matchGroup, null, 2));
The algorithm could look like this:
Start with a source - filter the db to all items that match. This is the "base-lvl0" (it ensures that our source cannot be ruled out later)
Take the 1. element from the "base-lvl0", and use it as the "source" for a second iteration to produce a "base-lvl1-1"
Take the 2. element from the "base-lvl0", and use it as the "source" for a second iteration to produce a "base-lvl1-2"
Take the 3. element from the "base-lvl0", and use it as the "source" for a second iteration to produce a "base-lvl1-3"
...
n. Take the nth element from the "base-lvl0" and use it as the "source" for a second iteration to produce a "base-lvl1-n"
By the nth step, you'll have a lot of smaller groups that are sure to satisfy at least 2 people. Now, do this with all the "base-lvl1-x" lists to create "base-lvl2-x" lists (to surely satisfy 3 people), then comes "base-lvl3-x", etc. up until all items from all lists have been used as "source".
This way you make sure that in all the FINAL lists everyone is in the preferential lists of everyone. I think this is a bit inefficient but deterministic & sure to satisfy the "location & preferred location" condition.
SUGGESTION:
Try to loosen up the conditions a bit or start to get deep into the beauties of graph theory.
This is quite cutting edge maths, and I think resembles your problem (in some ways): A Breakthrough in Graph Theory - Numberphile (2019)

Parsing array of objects to format data

I have an array of cities with this structure (given from the CMS):
const cities = [
{
city: 'Genova',
coordinates: '{\'type\':\'Point\',\'coordinates\':[8.9473343,44.4023918]}',
countryIsoCode: 'it',
description: 'test',
isInitialCity: true,
}, {
city: 'Barcelona',
coordinates: '{\'type\':\'Point\',\'coordinates\':[2.0951271,41.3397004]}',
countryIsoCode: 'es',
description: 'description',
isInitialCity: false,
}, {
city: 'Sydney',
coordinates: '{type\':\'Point\',\'coordinates\':[151.2158203,-33.8704156]}',
countryIsoCode: 'au',
description: 'Sydney description',
isInitialCity: false,
}];
I want to parse the coordinates position to get a more scalable object and get its properties nesting.
This is what I've tried:
cities.map(city=>JSON.parse(city.coordinates))
But when I print it seems to have no effect. However, if I manually print a position like console.log(JSON.parse(cities[0].coordinates)) it shows a formatted result like is shown in the following screenshot:
How can I make it automatically via loop?
This is what I've tried:
cities.map(city=>JSON.parse(city.coordinates))
map() created you a brand new, separate array with the coordinates only, which you have thrown away afterwards.
However, if I manually print a position like console.log(JSON.parse(cities[0].coordinates)) [...] How can I make it automatically via loop?
Well, put it in a loop:
for(let city of cities)
city.coordinates = JSON.parse(city.coordinates);
However your example data is syntactically incorrect, there are ,}-s at the end of the objects (after the true/false), and the supposed JSON data is not JSON, like
{type':'Point','coordinates':[151.2158203,-33.8704156]}
^it has no pair, and it should be double quote anyway, all of them
{"type":"Point","coordinates":[151.2158203,-33.8704156]} <-- this is JSON
What I think might be happening is that you're doing the map right but not returning the result.
For example mynumbers.map(num => num++) won't actually effect mynumbers at all. You have to assign the result of the map to another variable...
const parsedCities = cities.map(city=>JSON.parse(city.coordinates))
Now your new parsedCities variable will look like you want it to and the original cities array will remain unchanged.
const cities = [
{
city: 'Genova',
coordinates: '{\'type\':\'Point\',\'coordinates\':[8.9473343,44.4023918]}',
countryIsoCode: 'it',
description: 'test',
isInitialCity: true,
}, {
city: 'Barcelona',
coordinates: '{\'type\':\'Point\',\'coordinates\':[2.0951271,41.3397004]}',
countryIsoCode: 'es',
description: 'description',
isInitialCity: false,
}, {
city: 'Sydney',
coordinates: '{type\':\'Point\',\'coordinates\':[151.2158203,-33.8704156]}',
countryIsoCode: 'au',
description: 'Sydney description',
isInitialCity: false,
}];
//for(let city of cities)
// city.coordinates = JSON.parse(city.coordinates);
var x=cities.map(city=>JSON.parse(JSON.stringify(city.coordinates)))
console.log("result :"+(JSON.stringify(x)))
// result :["{'type':'Point','coordinates':[8.9473343,44.4023918]}","{'type':'Point','coordinates':[2.0951271,41.3397004]}","{type':'Point','coordinates':[151.2158203,-33.8704156]}"]

JS How to return all the people with the same last name

I'm new to coding and have been given this question, but I'm unsure to why my code doesn't work.
This is the question I have been given;
Create a function that takes an array of full names and returns an array containing only the people whose last name is Smith.
E.g. ['Charlotte Jones', 'Rebecca Smith', 'Harry Smith', 'John Smithy', 'Smith Jones'] => ['Rebecca Smith', 'Harry Smith']
This is the code that I have written;
function getSmiths(arr) {
return arr.filter(a =>a.includes("Smith"))
}
console.log(getSmiths(['Charlotte Jones', 'Rebecca Smith', 'Harry Smith', 'John Smithy', 'Smith Jones']));
my code is being run against this test;
describe("getSmiths", () => {
it("returns [] when passed []", () => {
expect(getSmiths([])).to.eql([]);
});
it("returns a Smith from a mixed arrau", () => {
expect(getSmiths(["Harry Smith", "Charlotte Bank"])).to.eql([
"Harry Smith"
]);
});
it("returns multiple Smiths from a mixed array", () => {
expect(getSmiths(["Harry Smith", "Charlotte Bank"])).to.eql([
"Harry Smith"
]);
});
it("ignores Smiths found in first names", () => {
expect(getSmiths(["Smithy Jones", "Harry Smith"])).to.eql(["Harry Smith"]);
});
it("ignores Smiths found in extended last names", () => {
expect(getSmiths(["John Smith", "Chris Smithy"])).to.eql(["John Smith"]);
});
});
Dose anyone have any suggestion to why my code doesn't work?
Well you're using include which will search for smith in the complete string.
Using endsWith
let arr = ['Charlotte Jones', 'Rebecca Smith', 'Harry Smith', 'John Smithy', 'Smith Jones'];
let op = arr.filter(e=> e.endsWith('Smith'))
console.log(op);
Using regex
let arr = ['Charlotte Jones', 'Rebecca Smith', 'Harry Smith', 'John Smithy', 'Smith Jones'];
let op = arr.filter(e=> /\ssmith$/ig.test(e))
console.log(op);
Have you seen specifically which tests in the test group are failing?
Your method to return all array members that include the string 'Smith' will return an array of items that have 'Smith' in them ANYWHERE, and will return the exact string.
In your 4th test of the group you will get back both array items, and as they are recorded (i.e. the second item will return as "Harry Smith".
In your last test, you will also get back both items, and the first item will be returned as "John Smith".
You need to change the test for your filter to only test against last name (hint: perhaps split each string and test against last name? - I'll let you work out how to do that).
I think that last test is always going to fail as you have written it. I suspect it was meant to return "John Smith" and you should be ensuring that "Smithy" fails the test. If so, you'll want to further your filter to ensure the last name EQUALS "Smith" rather than includes it.
Good luck!

React / Javascript - how to filter data received to a filtered list of columns?

I receive data / an array with objects. each object has country - city and shops (in that city).
For example:
USA - Los Angeles - shop1
Italy - Milan - shop2
Italy - Rome - shopXY
var data = [
{country: "Italy", city: "Milan", shop: "shop123"},
{country: "Italy", city: "Rome", shop: "shop2"},
{country: "USA", city: "Los Angeles", shop: "shopXY"}
]
I have 3 columns and I want to show only once Italy, then when I click on it, I show Milan and Rome, then based on whether I click Rome or Milan the corresponding shops.
Would it be good practise to:
get all the data, then create a new array of objects, so I dont have duplicate countries, cities etc.
Use filter method- but how could I filter it, how can check for duplicates
without storing them in a new array or the like?
Anything else?
I tried to research but couldn't really find anything and even if someone just has some tips, it would be great as I'm totally lost. Thanks!!!!
PS. I don't want to use any filter libraries for that as I m trying to do it myself.
I would recommend using a javascript object, as opposed to making a new array, with the processed data.
The property/value semantics of a Javascript object have following advantages
1.) Duplicates are automatically taken care of: Using the country as a key, you either create a new sub-object mapping shops to cities, or you simply expand an already present one
2.) Ease of access: Finding a Country/shop becomes as simple as data['Italy']['Rome']
Seems like a perfect fit for your use-case. The static way of defining such an object, in adherence to your example woud be:
var data = {
"Italy": {
"Milan": ["shop123"],
"Rome": ["shop2"]
},
"USA": {
"Los Angeles": ["shopXY"]
}
}
MTTI answers is good, and to get to it, I'd use a reduce
const newData = data.reduce((acc, val) => {
if (!acc[val.country]) {
acc[val.country] = { [val.city]: [val.shop] };
return acc;
}
if (!acc[val.country][val.city]) {
acc[val.country][val.city] = [val.shop];
return acc;
}
acc[val.country][val.city].push(val.shop);
return acc;
}, {})
So in the end you'll get an object like
{
Italy: {
Rome: ['Shop123'],
Milan: ['Shop12']
},
USA: {
"San Francisco": ['Shop420']
}
}
You can use the following script to filter the data after that you can iterate on the result of the script to show the data as you want.
var data = [{
country: "Italy",
city: "Milan",
shop: "shop123"
},
{
country: "Italy",
city: "Rome",
shop: "shop2"
},
{
country: "USA",
city: "Los Angeles",
shop: "shopXY"
},
]
var result = {};
data.forEach(function (item) {
if (result[item.country]) {
result[item.country][item.city] = item.shop
} else {
result[item.country] = {};
result[item.country][item.city] = item.shop
}
});
The out put will be like -
{
"Italy": {
"Milan": "shop123",
"Rome": "shop2"
},
"USA": {
"Los Angeles": "shopXY"
}
}

Categories

Resources