迭代设计糟糕的 API,其中对象键由文本和数字组成

eGa*_*ood 1 javascript jquery javascript-objects

目前正在开发一个用于搜索饮料配方的网络应用程序。这个想法是搜索一种饮料并向用户显示名称、成分和尺寸。我正在努力寻找一种有效的方法来迭代 API 响应,因为它们不会以数组形式返回。下面是一个响应示例。

dateModified :"2015-08-18 14:54:32"   
idDrink:"11668"    
strAlcoholic:"Alcoholic
strCategory:"Ordinary Drink"
strDrink: "Long Island Tea"
strDrinkThumb:  "https://www.thecocktaildb.com/images/media/drink/ywxwqs1439906072.jpg"
strGlass: "Highball glass"
strIBA:null
strIngredient1: "Vodka"
strIngredient2:"Light rum"
strIngredient3:"Gin" 
strIngredient4:"Tequila"  
strIngredient5: "Lemon"
strIngredient6: "Coca-Cola" 
strIngredient7:""
strIngredient8:""
strIngredient9:""
strIngredient10:""
strIngredient11:""
strIngredient12:""
strIngredient13:""
strIngredient14:""
strIngredient15:""
strInstructions: 
"Combine all ingredients (except cola) and pour over ice in a highball glass. Add the splash of cola for color. Decorate with a slice of lemon and serve." 
strMeasure1:"1/2 oz "
strMeasure2:"1/2 oz "
strMeasure3: "1/2 oz "
strMeasure4: "1/2 oz "
strMeasure5:"Juice of 1/2 "
strMeasure6:"1 splash "
strMeasure7:" "
strMeasure8:" "
strMeasure9:" "
strMeasure10:" "
strMeasure11:" "
strMeasure12:" "
strMeasure13:" "
strMeasure14:" "
strMeasure15:" "
strVideo: null
Run Code Online (Sandbox Code Playgroud)

目标是将一些信息映射到表中。是否有一种迭代方法来清理这个问题,以便只返回具有值的成分?或者创建一个单独的文件来格式化成分是最好的解决方案吗?

目前,我能想到的阻力最小的路径是创建以下 15 次:strIngredient1 !=""

下面是API调用:

$('#drinkSearch').click(function(){
  var word = document.getElementById("sbar").value;

  event.preventDefault();
  console.log(word)
  $.getJSON("https://www.thecocktaildb.com/api/json/v1/1/search.php?s="+ word, function(Result) {
    console.log(Result)
    Result.drinks.forEach(function(ingredients){
       var ing1 = ingredients.strIngredient1;

       console.log(ing1);
    })
  });
});
Run Code Online (Sandbox Code Playgroud)

Seb*_*mon 5

API 会为每种饮料返回一个对象,其中包含诸如strIngredient1through之类的键strIngredient15strMeasure1throughstrMeasure15等键。\xe2\x80\x8a\xe2\x80\x94\xe2\x80\x8a 的设计确实很糟糕。

\n\n

您可以将所有这些收集到一个数组中。有两种不同的处理空值的方法。您可以简单地过滤空值将度量与其成分相匹配

\n\n

简单过滤空值

\n\n

这些方法只是从每个要构建的数组中删除空值。这可能会导致不一致,因为键实际上在位置上strMeasure依赖于strIngredient键。寻找匹配的方法来解决这个问题。

\n\n

另一个问题是成分和措施有时可能会出现问题。配套\xe2\x80\x99没有这个问题。

\n\n
Result.drinks.forEach((drink) => {\n  const drinkEntries = Object.entries(drink),\n    ingredientsArray = drinkEntries\n      .filter(([key, value]) => key.startsWith("strIngredient") && value && value.trim())\n      .map(([key, value]) => value),\n    measuresArray = drinkEntries\n      .filter(([key, value]) => key.startsWith("strMeasure") && value && value.trim())\n      .map(([key, value]) => value);\n\n  console.log("Ingredients:", ingredientsArray);\n  console.log("Measures:", measuresArray);\n});\n
Run Code Online (Sandbox Code Playgroud)\n\n

在 中filterkey.startsWith("strIngredient")确保您获得正确的十五个键,并&& value && value.trim()确保该值既不是null,也不是空,也不是空格(因此trim)。所有三种变体都是随机使用的。

\n\n

冗余较少的形式可能如下所示:

\n\n
Result.drinks.forEach((drink) => {\n  const drinkEntries = Object.entries(drink),\n    [\n      ingredientsArray,\n      measuresArray\n    ] = [\n      "strIngredient",\n      "strMeasure"\n    ].map((keyName) => drinkEntries\n      .filter(([key, value]) => key.startsWith(keyName) && value && value.trim())\n      .map(([key, value]) => value));\n\n  console.log("Ingredients:", ingredientsArray);\n  console.log("Measures:", measuresArray);\n});\n
Run Code Online (Sandbox Code Playgroud)\n\n

将措施与其成分相匹配

\n\n

这种方法首先为strIngredients 和strMeasures 构建两个数组。数字键用 提取parseInt(key.slice(keyName.length))Object.assign将多个{key: value}对象放入一个数组中(其中keys 是数字)意味着使用这些数字键和这些值构建一个数组。1

\n\n

然后对值进行过滤,以便如果有任何具有相同索引的值,则保留它们值非空时保留这些值。

\n\n
Result.drinks.forEach((drink) => {\n  const drinkEntries = Object.entries(drink),\n    // This part build arrays out of the two sets of keys\n    [\n      ingredientsArray,\n      measuresArray\n    ] = [\n      "strIngredient",\n      "strMeasure"\n    ].map((keyName) => Object.assign([], ...drinkEntries\n        .filter(([key, value]) => key.startsWith(keyName))\n        .map(([key, value]) => ({[parseInt(key.slice(keyName.length))]: value})))),\n\n    // This part filters empty values based on the ingredients\n    {\n      finalIngredients,\n      finalMeasures\n    } = ingredientsArray.reduce((results, value, index) => {\n      if(value && value.trim() || measuresArray[index] && measuresArray[index].trim()){\n        results.finalIngredients.push(value);\n        results.finalMeasures.push(measuresArray[index]);\n      }\n\n      return results;\n    }, {\n      finalIngredients: [],\n      finalMeasures: []\n    }),\n\n    // Optional: zip both arrays\n    ingredientsWithMeasures = finalIngredients\n      .map((value, index) => [finalMeasures[index], value]);\n\n  // Output\n  console.log("Ingredients:", finalIngredients);\n  console.log("Measures:", finalMeasures);\n\n  console.log("All ingredients and measures:\\n", ingredientsWithMeasures\n    .map(([measure, ingredient]) => `${(measure || "").trim()} ${(ingredient || "").trim()}`)\n    .join("\\n"));\n});\n
Run Code Online (Sandbox Code Playgroud)\n\n
\n\n

1:从对象构建数组通常也适用于Array.from,但它length也需要一个属性。我没有计算,而是继续使用Object.assign

\n