【问题标题】:Filter 2 arrays return based on matching inner values javascript根据匹配的内部值javascript过滤2个数组返回
【发布时间】:2021-12-29 00:01:13
【问题描述】:

我有 2 个数组 bodypartsequipment
数组对象已放入下拉菜单中。
我正在尝试 filter 基于对象值的结果
例如。如果我从bodyparts array 中选择“胸”,从equipment array 中选择“杠铃”,我只希望在console 中出现匹配值来自“胸”和“杠铃”的结果。

这是数组对象的样子
{bodyPart: 'neck', equipment: 'body weight', id: '1403', name: 'neck side stretch', …}

const dataDiv = document.getElementById("data")
const apiURL = 'https://exercisedb.p.rapidapi.com/exercises/bodyPart/%7Bchest%7D'

let mainList = []
let bodypartsList = []
let equipmentList = []


async function getApiURL(endpoint, value) {
    console.log(`https://exercisedb.p.rapidapi.com/exercises/${endpoint}/${value}`);
    const response = await fetch(`https://exercisedb.p.rapidapi.com/exercises/${endpoint}/${value}`, {
        "method": "GET",
        "headers": {
            "x-rapidapi-host": "exercisedb.p.rapidapi.com",
            "x-rapidapi-key": "myApiKey"
        }
    })
    const data = await response.json();
    if (endpoint == "bodypart") {
        bodypartsList = data
    } else {
        equipmentList = data
    }
    mergeLists()
}

function mergeLists() {
    mainList = bodypartsList.concat(equipmentList);
    displayData(mainList)
}


//bodypart code
const bodyparts = ["Body Parts", "back", "cardio", "chest", "lower arms", "lower legs", "neck", "shoulders", "upper arms", "upper legs", "waist"]
const equipment = ["Equipment", "assisted", "band", "barbell", "body weight", "cable", "dumbbell", "ez barbell", "hammer", "kettlebell", "leverage machine", "medicine ball", "resistance band", "roller", "rope", "smith machine", "tire", "trap bar", "weighted"]


const exercises = document.getElementById("exercises");


window.addEventListener("load", function () {
    createDropdown("bodypart", bodyparts);
})
window.addEventListener("load", function () {
    createDropdown("equipment", equipment);
})

// const select = document.createElement("select"); //---create the select element
// const option = document.createElement("option"); //---create options for select

function createDropdown(name, items) {
    const select = document.createElement("select"); //---create the select element
    select.className = "selectMenu"
    select.name = name
    select.id = name
    for (let i = 0; i < items.length; i++) { //---as long as 'i' is less than the number of items increase by 1
        const item = items[i]; //---declaring 'i' as items
        const option = document.createElement("option"); //---create options for select
        option.setAttribute("value", item); //---places item value into options
        option.innerHTML = item; //---change content of options to items
        select.appendChild(option); //---append options to select

    }
    exercises.appendChild(select); //---append data to options


    select.addEventListener("change", function () {
        const item = select.value;
        dataDiv.innerHTML = ''; //<------Clears previous results from page
        // console.log(item);
        getApiURL(name, item);
    })
}


function displayData(data) {
    // console.log(data);
    let d1 = document.getElementById("equipment")
    let d2 = document.getElementById("bodypart")

    console.log(d2.value);

    if (d2.value && d1.value !== -1 ){
    const result = data.filter(word => {
        return (word.name.indexOf(d1.value))
    });
   
    console.log(result);
    
    result.forEach(element => {
        const div = document.createElement("div");
        const p = document.createElement("p");
        // const img = document.createElement("img");
        // img.className = "appGifs"
        p.innerHTML = element.name
        // img.src = element.gifUrl
        div.appendChild(p)
        // div.appendChild(img)
        div.className = "card"
        dataDiv.appendChild(div)
    
    });
}
}

HTML

<div class="row-md-6 offset-md-2">
  <div class="col-sm-10" style="border:1px solid blue">
    Logo goes here 

    <div class="row">
      <div class="col-8 col-sm-6" style="border:1px solid red">
        <div id="exercises" class="bg-primary align-items-center"></div> <!--Dropdown Buttons-->
        
      </div>
      <div class="col-4 col-sm-6" style="border:1px solid red">
        <div id="data"></div> <!--Result Data-->
      </div>
    </div>
  </div>
</div>

<div id="appSubmit"></div> <!--Submit button-->

它目前正在显示所有合并的结果,我认为它正在将过滤结果添加到 mainList array 而不是删除不需要的结果。
我真的找不到我做错了什么,感谢任何帮助

谢谢

【问题讨论】:

  • 你能稍微简化一下你的问题吗?你写了这个。老实说,我不知道你说什么,好吧
  • 我在底部添加了html
  • 我的意思是,你能否保持你的问题简洁明了
  • @Dave 您发布的 JS 代码,我认为它不完整。您能否提供一个可重现的最小示例?
  • 刚刚更新了js

标签: javascript arrays filter


【解决方案1】:

所以我从If I select 'chest' from bodyparts array and 'barbell' from equipment array I only want results with matching values from 'chest' and 'barbell' to appear in the console. 这一行了解到,如果您从下拉列表中选择胸部,您希望显示名称与所选值匹配的所有数据。

你正在这样做:

    const result = data.filter(word => {
        return (word.name.indexOf(d1.value))
    });

indexOf() 方法返回第一次出现的位置 字符串中的指定值。 indexOf() 方法返回 -1 如果值 没有找到。

它永远不会返回您期望的结果。因此,您可以尝试这样的事情,而不是这样做:

const result = data.filter(word => word.name.includes(d2.value)); 

这将返回与 D2 下拉列表中所选值匹配的所有值。对于 d1,您也需要这样做。

更新

用这个改变你的显示功能

function displayData(data) {
    debugger;
    // console.log(data);
    let d1 = document.getElementById("equipment");
    let d2 = document.getElementById("bodypart");

    console.log(d2.value);

    let value1;
    let value2;

    //get filtered value for d2
    if (d2.value){
        value2 = data.filter(word => word.name.includes(d2.value));
    }
    ////get filtered value for d1
    if (d1.value){
        value1 = data.filter(word => word.name.includes(d1.value));
    }

    //merge both the value into one using spread operator(... this is called spread operator in JS)
    let result = [
        ...value1,
        ...value2
   ];

   //loop over the final result
    if(result.length > 0){
        console.log(result);
        debugger;
        result.forEach(element => {
            debugger;
            const div = document.createElement("div");
            const p = document.createElement("p");
            // const img = document.createElement("img");
            // img.className = "appGifs"
            p.innerHTML = element.name
            // img.src = element.gifUrl
            div.appendChild(p)
            // div.appendChild(img)
            div.className = "card"
            dataDiv.appendChild(div)
        
        });
    }
}

【讨论】:

  • 感谢这让我更进一步,我现在得到过滤结果,但它们显示为双精度。
  • @Dave 值在下拉列表中或仅在特定下拉列表中显示为双精度值?
  • 它显示了 2 个过滤结果。从每个下拉列表中选择一个选项后,双重结果显示在单独的 div 中
  • 没关系,我刚刚找到了双重结果的解决方案。再次感谢您的解决方案
  • @Dave 我更新了 displayData 函数,看看
【解决方案2】:

您正在混合字符串和索引。我还假设您不想像其他发布的答案那样使用 0 索引进行过滤。

let result = data;
if (d1.selectedIndex > 0) {
 const selected = d1.value;
 result = result.filter(({equipment}) => equipment.includes(selected));
}

if (d2.selectedIndex > 0) {
 const selected = d2.value;
 result = result.filter(({bodyPart}) => bodyPart.includes(selected));
}

【讨论】:

  • 感谢您的回答,在其他人修复后我最终遇到了一些其他问题,所以我尝试了这个,它完成了我需要它做的 99%。超级开心
【解决方案3】:

我认为问题在于你的函数displayData中的if条件

if (d2.value && d1.value !== -1 ){
const result = data.filter(word => {
    return (word.name.indexOf(d1.value))
});

如果d1.valueword.name不匹配,则条件返回-1,而不是0,也就是说即使不匹配,也返回true(-1表示true,只有0表示false) .

所以你可以简单地将这个条件更改为

return word.name.indexOf(d1.value) !== -1

【讨论】:

    【解决方案4】:

    在 js 中,数组和对象等非基元是通过引用传递的,所以当你想比较两个数组时,你必须改变数据类型。 您必须将对象和数组更改为字符串,然后进行比较。使用 JSON.stringify 来做到这一点。下面的代码只是一个示例:

    const arr1 = []
    const arr2 = [] 
    console.log(arr1 === arr2) //false
    
    console.log(JSON.stringify(arr1) === JSON.stringify(arr2)) //true
    

    【讨论】:

      猜你喜欢
      • 2018-08-06
      • 1970-01-01
      • 1970-01-01
      • 2011-10-19
      • 1970-01-01
      • 1970-01-01
      • 2012-03-12
      • 1970-01-01
      • 2023-03-14
      相关资源
      最近更新 更多