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

8hhllhi2  于 2023-08-04  发布在  jQuery
关注(0)|答案(4)|浏览(81)

目前正在开发一个用于搜索饮料配方的网络应用程序。这个想法是搜索一种饮料,并将名称、成分和尺寸显示给用户。我正在努力寻找一种有效的方法来迭代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

字符串
目标是将一些信息Map到一个表。有没有一种迭代的方法来清理这个问题,以便只返回有值的成分?或者最好的解决方案是创建一个单独的文件来格式化成分?
目前,我能想到的阻力最小的路径是创建以下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);
    })
  });
});

qv7cva1a

qv7cva1a1#

该API为每个饮料返回一个对象,其中包含strIngredient1strIngredient15strMeasure1strMeasure15等键-确实设计得很糟糕。  
你可以把所有这些放在一个数组中。处理空值有两种不同的方法。您可以简单地过滤空值将度量值与其成分匹配

简单过滤空值

这些方法只是从每个要构建的数组中删除空值。这可能会导致不一致,因为strMeasure键实际上依赖于strIngredient键,* 位置上 *。寻找下面的匹配方法来解决这个问题。
另一个问题是,成分和措施有时可能是无序的。匹配方法不存在此问题。

Result.drinks.forEach((drink) => {
  const drinkEntries = Object.entries(drink),
    ingredientsArray = drinkEntries
      .filter(([key, value]) => key.startsWith("strIngredient") && value && value.trim())
      .map(([key, value]) => value),
    measuresArray = drinkEntries
      .filter(([key, value]) => key.startsWith("strMeasure") && value && value.trim())
      .map(([key, value]) => value);

  console.log("Ingredients:", ingredientsArray);
  console.log("Measures:", measuresArray);
});

字符串
filter中,key.startsWith("strIngredient")确保您获得正确的15个键,&& value && value.trim()确保值既不是null,也不是空的,也不是空白(因此是trim)。所有三种变化都是随机使用的。
一个不那么冗余的表单可能看起来像这样:

Result.drinks.forEach((drink) => {
  const drinkEntries = Object.entries(drink),
    [
      ingredientsArray,
      measuresArray
    ] = [
      "strIngredient",
      "strMeasure"
    ].map((keyName) => drinkEntries
      .filter(([key, value]) => key.startsWith(keyName) && value && value.trim())
      .map(([key, value]) => value));

  console.log("Ingredients:", ingredientsArray);
  console.log("Measures:", measuresArray);
});

将度量值与度量值的成分匹配

这种方法首先为strIngredient s和strMeasure s构建两个数组。使用parseInt(key.slice(keyName.length))提取数字键。Object.assign将几个{key: value}对象放到一个数组中,其中key是数字,这意味着用这些数字键和值构建一个数组。
然后过滤这些值,使得如果具有 * 相同索引 * 的 * 任何 * 值非空,则它们保留。

Result.drinks.forEach((drink) => {
  const drinkEntries = Object.entries(drink),
    // This part build arrays out of the two sets of keys
    [
      ingredientsArray,
      measuresArray
    ] = [
      "strIngredient",
      "strMeasure"
    ].map((keyName) => Object.assign([], ...drinkEntries
        .filter(([key, value]) => key.startsWith(keyName))
        .map(([key, value]) => ({[parseInt(key.slice(keyName.length))]: value})))),

    // This part filters empty values based on the ingredients
    {
      finalIngredients,
      finalMeasures
    } = ingredientsArray.reduce((results, value, index) => {
      if(value && value.trim() || measuresArray[index] && measuresArray[index].trim()){
        results.finalIngredients.push(value);
        results.finalMeasures.push(measuresArray[index]);
      }

      return results;
    }, {
      finalIngredients: [],
      finalMeasures: []
    }),

    // Optional: zip both arrays
    ingredientsWithMeasures = finalIngredients
      .map((value, index) => [finalMeasures[index], value]);

  // Output
  console.log("Ingredients:", finalIngredients);
  console.log("Measures:", finalMeasures);

  console.log("All ingredients and measures:\n", ingredientsWithMeasures
    .map(([measure, ingredient]) => `${(measure || "").trim()} ${(ingredient || "").trim()}`)
    .join("\n"));
});


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

2izufjch

2izufjch2#

替代解决方案可以是:

result.drinks.forEach(function(ingredients){
   var ing = Object.keys(ingredients).reduce(function(a, ele) {
       if (ele.startsWith('strIngredient') && ingredients[ele].trim() != '') {
           if (!a[ingredients.strDrink]) a[ingredients.strDrink] = [];
           a[ingredients.strDrink].push(ingredients[ele]);
       }
       return a;
   }, {});
   console.log(Object.keys(ing)[0] + ': ' + ing[Object.keys(ing)[0]].join(', '));

字符串
})

var result= {
    "drinks": [{
        "idDrink": "12734",
        "strDrink": "Chocolate Drink",
        "strVideo": null,
        "strCategory": "Cocoa",
        "strIBA": null,
        "strAlcoholic": "Non alcoholic",
        "strGlass": "Coffee mug",
        "strInstructions": "Melt the bar in a small amount of boiling water. Add milk. Cook over low heat, whipping gently (with a whisk, i would assume) until heated well. Don't let it boil! Serve in coffee mug.",
        "strDrinkThumb": "https:\/\/www.thecocktaildb.com\/images\/media\/drink\/q7w4xu1487603180.jpg",
        "strIngredient1": "Chocolate",
        "strIngredient2": "Milk",
        "strIngredient3": "Water",
        "strIngredient4": "",
        "strIngredient5": "",
        "strIngredient6": "",
        "strIngredient7": "",
        "strIngredient8": "",
        "strIngredient9": "",
        "strIngredient10": "",
        "strIngredient11": "",
        "strIngredient12": "",
        "strIngredient13": "",
        "strIngredient14": "",
        "strIngredient15": "",
        "strMeasure1": "125 gr",
        "strMeasure2": "3\/4 L ",
        "strMeasure3": "",
        "strMeasure4": "",
        "strMeasure5": "",
        "strMeasure6": "",
        "strMeasure7": "",
        "strMeasure8": "",
        "strMeasure9": "",
        "strMeasure10": "",
        "strMeasure11": "",
        "strMeasure12": "",
        "strMeasure13": "",
        "strMeasure14": "",
        "strMeasure15": "",
        "dateModified": "2017-02-20 15:06:20"
    }, {
        "idDrink": "12736",
        "strDrink": "Drinking Chocolate",
        "strVideo": null,
        "strCategory": "Cocoa",
        "strIBA": null,
        "strAlcoholic": "Non alcoholic",
        "strGlass": "Coffee mug",
        "strInstructions": "Heat the cream and milk with the cinnamon and vanilla bean very slowly for 15-20 minutes. (If you don't have any beans add 1-2 tsp of vanilla after heating). Remove the bean and cinnamon. Add the chocolate. Mix until fully melted. Serve topped with some very dense fresh whipped cream. Serves 1-2 depending upon how much of a glutton you are. For a richer chocolate, use 4 oz of milk, 4 oz of cream, 4 oz of chocolate. Serve in coffee mug.",
        "strDrinkThumb": "https:\/\/www.thecocktaildb.com\/images\/media\/drink\/u6jrdf1487603173.jpg",
        "strIngredient1": "Heavy cream",
        "strIngredient2": "Milk",
        "strIngredient3": "Cinnamon",
        "strIngredient4": "Vanilla",
        "strIngredient5": "Chocolate",
        "strIngredient6": "Whipped cream",
        "strIngredient7": "",
        "strIngredient8": "",
        "strIngredient9": "",
        "strIngredient10": "",
        "strIngredient11": "",
        "strIngredient12": "",
        "strIngredient13": "",
        "strIngredient14": "",
        "strIngredient15": "",
        "strMeasure1": "2 oz ",
        "strMeasure2": "6-8 oz ",
        "strMeasure3": "1 stick ",
        "strMeasure4": "1 ",
        "strMeasure5": "2 oz finely chopped dark ",
        "strMeasure6": "Fresh ",
        "strMeasure7": " ",
        "strMeasure8": " ",
        "strMeasure9": " ",
        "strMeasure10": " ",
        "strMeasure11": " ",
        "strMeasure12": "",
        "strMeasure13": "",
        "strMeasure14": "",
        "strMeasure15": "",
        "dateModified": "2017-02-20 15:06:13"
    }, {
        "idDrink": "12690",
        "strDrink": "Lassi - A South Indian Drink",
        "strVideo": null,
        "strCategory": "Other\/Unknown",
        "strIBA": null,
        "strAlcoholic": "Non alcoholic",
        "strGlass": "Highball Glass",
        "strInstructions": "Blend in a blender for 3 seconds. Lassi is one of the easiest things to make, and there are many ways of making it. Basically, it is buttermilk (yoghurt whisked with water), and you can choose almost any consistency that you like, from the thinnest to the thickest. Serve cold.",
        "strDrinkThumb": "https:\/\/www.thecocktaildb.com\/images\/media\/drink\/iq6scx1487603980.jpg",
        "strIngredient1": "Yoghurt",
        "strIngredient2": "Water",
        "strIngredient3": "Cumin seed",
        "strIngredient4": "Salt",
        "strIngredient5": "Mint",
        "strIngredient6": "",
        "strIngredient7": "",
        "strIngredient8": "",
        "strIngredient9": "",
        "strIngredient10": "",
        "strIngredient11": "",
        "strIngredient12": "",
        "strIngredient13": "",
        "strIngredient14": "",
        "strIngredient15": "",
        "strMeasure1": "1\/2 cup plain ",
        "strMeasure2": "1 1\/4 cup cold ",
        "strMeasure3": "1\/2 tsp ground roasted ",
        "strMeasure4": "1\/4 tsp ",
        "strMeasure5": "1\/4 tsp dried ",
        "strMeasure6": " ",
        "strMeasure7": " ",
        "strMeasure8": " ",
        "strMeasure9": " ",
        "strMeasure10": " ",
        "strMeasure11": "",
        "strMeasure12": "",
        "strMeasure13": "",
        "strMeasure14": "",
        "strMeasure15": "",
        "dateModified": "2017-02-20 15:19:40"
    }]
};

result.drinks.forEach(function(ingredients){
    var ing = Object.keys(ingredients).reduce(function(a, ele) {
        if (ele.startsWith('strIngredient') && ingredients[ele].trim() != '') {
            if (!a[ingredients.strDrink]) a[ingredients.strDrink] = [];
            a[ingredients.strDrink].push(ingredients[ele]);
        }
        return a;
    }, {});
    console.log(Object.keys(ing)[0] + ': ' + ing[Object.keys(ing)[0]].join(', '));

})

ux6nzvsh

ux6nzvsh3#

我喜欢Xufox的回答,这里有另一种驯服API的可能性,通过对manhattan的硬编码调用:)这里的想法是将各种东西编组到包含有用数据的最终recipe中。
注意,我重构了这个函数,以展示如何(也许应该)将Map提取到一个单独的函数中。

const word = 'manhattan';
const url = `https://www.thecocktaildb.com/api/json/v1/1/search.php?s=${word}`;


$.getJSON(url, (result) => {
  const recipes = result.drinks.map(extractRecipe);
  console.log(recipes);
})

// do your mapping in a defined function.
function extractRecipe(drink) {
  const recipe = {
    name: drink.strDrink,
    glass: drink.strGlass,
    instructions: drink.strInstructions,
    thumbnail: drink.strDrinkThumb
  };

  Object.keys(drink)
    .filter(key => key.substring(0, 13) === 'strIngredient')
    .filter(key => drink[key].trim())
    .reduce((ingredients, ingredient) => ingredients.concat(ingredient), [])
    .forEach((key, index) => {
      let ingIndex = index + 1;
      recipe[drink[key]] = drink[`strMeasure${ingIndex}`];
    })
  return recipe;
}

个字符

7gs2gvoe

7gs2gvoe4#

更简单的解决方案相信你已经从cocktail API获得了成功的响应,简单的方法是考虑替换drinks[0].strIngredient{num}末尾的数字并检查值是否为null,如果值为null,你可以忽略它并打印非null值。我有一个代码片段如下::

我已经测试过了,这适用于其他参数

<div class="secondFloat">
            <% for(let i=1;i<=15;i++) { %>
                <% let ingredient = content.drinks[0][`strIngredient${i}`] %>
                <% if(ingredient !== null){ %>
                    <h1><%=ingredient%></h1>
                <%} %>
            <%} %>

字符串
JSON也是如此。希望这有帮助!!!

相关问题