如何在JavaScript/TypeScript中从嵌套if-else切换



最初我试图进行切换,但在接下来的几行中,我将解释为什么它不能这样工作。

有两个像这样的阵列:

const countries = [ 'France', 'Italy', 'Spain' ];
const cities = [ 'Paris', 'Marseille', 'Rome', 'Naples', 'Milan', 'Madrid' ];

正如你所看到的,国家和城市之间存在着联系:

  • 法国有巴黎和马赛
  • 意大利有罗马、那不勒斯和米兰
  • 西班牙有马德里

我的应用程序的逻辑应该按字母顺序(F>I>S(检查这些国家/地区,然后检查是否有可用的城市。

如果存在一个国家,但没有提供城市,则默认情况下应使用首都(列表中的第一个(。如果有多个城市,则应检查首都的最后一个城市。

示例:


输入:countries = [ 'France' ]; cities = [ 'Marseille']

结果:doThis('Marseille');


输入:countries = [ 'France' ]; cities = []

结果:doThis('Paris');


输入:countries = [ 'France' ]; cities = [ 'Paris', 'Marseille']

结果:doThis('Marseille');

这是代码:

const doThat = (city: string) => {
console.log(city);
};
const myFunc = (countries: string[], cities: string[]) => {
if (countries.includes('France')) {
if (cities.includes('Marseille')) {
doThat('Marseille');
} else doThat('Paris');
} else if (countries.includes('Italy')) {
if (cities.includes('Naples')) {
doThat('Naples');
} else if (cities.includes('Milan')) {
doThat('Naples');
} else doThat('Rome');
} else if (countries.includes('Spain')) {
doThat('Madrid');
} else doThat('empty');
};

它不能与交换机一起工作,因为它会像一样

switch (countries) {
case countries.includes('France'): ... // cannot be boolean here
...
}

有没有办法让它变得更好/更可读?

这是我写的一篇关于它的文章!使用映射重构

长话短说:使用Maps!在您的具体情况下,您可能需要<string, string[]>的地图。

因此,在您的代码中,您将拥有:

for(country in countries){
const mappedCities = contryMap.get(country)
// find either the first city which is in both the passed array and the map 
// or default to the first one
const cityIndex = Math.max(0, mappedCities.findIndex(city => 
cities.includes(city)))
doThat(mappedCities[cityIndex]
}

在一个单独的文件中:

export const cityMap = new Map<string, string[]>([
['france', ['Paris', 'Marseille']],
]) 

试试这个。

const myFunc = (countries: string[], cities: string[]) => {
for(const country of countries) {
switch(country) {
case "France": {
if(cities.includes("Marseille")){
doThat("Marseille");
break;
}
// If no cities are provided, use the capital city
doThat("Paris");
break;
};
case "Italy": {
if(cities.includes("Naples")) {
doThat("Naples");
break;
} else if (cities.includes("Milan")) {
doThat("Milan")
break;
} 
// If no cities are provided, use the capital city
doThat("Rome")
break;
};
case "Spain": {
// Since there is only one city (i.e. the capital) for Spain
doThat("Madrid")
break;
}
default: 
// If no matching country is passed, send "empty"
doThat("empty");
break;
}
}
};

与其将数据硬编码到代码中,不如将您所在的国家/地区和城市放入一个结构中,然后选择城市。

const country_cities = {
"France": ["Paris", "Marseille", "Lyon"],
"Italy": ["Rome", "Naples"],
"Spain": ["Madrid"],
};
const choose_city = (countries, cities) => {
countries = [...countries].sort()
for (let country of countries) {
if (!country_cities.hasOwnProperty(country)) { // ignore unknown countries
continue;
}
let [capital, ...other_cities] = country_cities[country]; // split recognised cities into the capial and other cities
const other_city = cities.find(city => other_cities.includes(city)); // if any of the other cities was provided
if (other_city) {
return other_city;
}
return capital;
}
return "empty";
};
const tests = [
[["France"], ["Marseille"], "Marseille"], // return the only country's city
[["France"], ["Paris"], "Paris"], // return the only country's city
[["France"], [], "Paris"], // no city, defaults to capital
[["France"], ["Marseille", "Paris"], "Marseille"], // return non-capital
[["France"], ["Paris", "Lyon", "Marseille"], "Lyon"], // return first non-capital
[["France"], ["Paris", "Marseille", "Lyon"], "Marseille"], // return first non-capital
[["Spain"], ["Barcelona"], "Madrid"], // no recognised Spanish city, defaults to capital
[["Germany"], ["Berlin"], "empty"], // unknown country, defaults to "empty"
[["Spain", "France"], ["Marseille", "Madrid"], "Marseille"], // return first French city
[["Spain", "France"], ["Naples", "Madrid"], "Paris"], // no French city, defaults to capital
[["Germany", "Italy"], ["Berlin", "Naples"], "Naples"], // Italy first recognised country, returns Italian city
[["Germany", "Italy"], ["Berlin"], "Rome"], // Italy first recognised country, no Italian city, returns capital
];
document.querySelector("#do-this").addEventListener("click", function(e) {
const countries = [...document.querySelectorAll("#countries option:checked")].map(o => o.value);
const cities = [...document.querySelectorAll("#cities option:checked")].map(o => o.value);
document.querySelector("#result-countries").textContent = countries.join(", ");
document.querySelector("#result-cities").textContent = cities.join(", ");
const city = choose_city(countries, cities);
document.querySelector("#result").textContent = city;
});
document.querySelector("#run-tests").addEventListener("click", function(e) {
const output = document.querySelector("#result-tests");
output.textContent = "";
for (let [countries, cities, true_result] of tests) {
const result = choose_city(countries, cities);
if (result === true_result) {
output.textContent += `countries: ${countries}ncities: ${cities}nresult: ${result} (OK)nn`;
}
else {
output.textContent += `countries: ${countries}ncities: ${cities}nresult: ${result} (should be ${true_result})nn`;
}
}
});
<div style="display: flex; gap: 0 1em;">
<div>
<select id="countries" multiple size="6">
<optgroup label="Unknown">
<option>Germany</option>
</optgroup>
<optgroup label="Known">
<option>Italy</option>
<option>Spain</option>
<option>France</option>
</optgroup>
</select>
<select id="cities" multiple size="9">
<optgroup label="Unknown">
<option>Berlin</option>
</optgroup>
<optgroup label="Known">
<option>Paris</option>
<option>Marseille</option>
<option>Lyon</option>
<option>Rome</option>
<option>Naples</option>
<option>Madrid</option>
</optgroup>
</select>
<br>
<button id="do-this">Do this</button>
<div>Countries: <span id="result-countries"></span></div>
<div>Cities: <span id="result-cities"></span></div>
<div>Done this: <span id="result"></span></div>
</div>
<pre id="result-tests">
<button id="run-tests">Run tests</button>
</pre>
</div>

最新更新