如何在深嵌套数组中找到具有id值的对象?

时间:2018-03-15 20:19:20

标签: javascript object find lodash

鉴于这种结构,我如何在这个深层嵌套的对象结构中找到具有给定id的对象。

const menuItems = [
    {
        id: 1,
        imageUrl: "http://placehold.it/65x65",
        display: "Shop Women",
        link: "#",
        type: "image",
        nextItems: [
            {
                id: 10,
                display: "홈",
                link: "#",
                type: "menuitem"
            },
            {
                id: 20,
                display: "의류",
                link: "#",
                type: "menuitem-withmore",
                nextItems: [
                    {
                        id: 100,
                        display: "I'm inside one nest",
                        link: "#",
                        type: "menuitem"
                    }
                ]
            },
            {
                id: 30,
                display: "가방",
                link: "#",
                type: "menuitem-withmore",
                nextItems: []
            },
            {
                id: 40,
                display: "신발",
                link: "#",
                type: "menuitem-withmore",
                nextItems: []
            },
            {
                id: 50,
                display: "악세서리",
                link: "#",
                type: "menuitem-withmore",
                nextItems: []
            },
            {
                id: 60,
                display: "SALE",
                link: "#",
                type: "menuitem-withmore",
                style: "bold",
                nextItems: []
            },
            {
                id: 70,
                display: "브랜드",
                link: "#",
                type: "menuitem-withmore",
                nextItems: []
            },
            {
                type: "separator"
            },
            {
                id: 80,
                display: "위시리스트",
                link: "#",
                type: "menuitem"
            },
            {
                id: 90,
                display: "고객센터",
                link: "#",
                type: "menuitem"
            },
            {
                id: 99,
                display: "앱 다운로드",
                link: "#",
                type: "menuitem"
            }
        ]
    },
    {
        id: 2,
        imageUrl: "http://placehold.it/65x65",
        display: "Shop Men",
        link: "#",
        type: "image",
        nextItems: [
            {
                id: 95,
                display: "MEN's ITEMS.",
                link: "#",
                type: "menuitem"
            }
        ]
    }
];

让我们说我想找到id: 20的对象并将其返回:

        {
            id: 20,
            display: "의류",
            link: "#",
            type: "menuitem-withmore",
            nextItems: [
                {
                    id: 100,
                    display: "I'm inside one nest",
                    link: "#",
                    type: "menuitem"
                }
            ]
        },

我似乎无法找到如何使用lodash,而且这个软件包可能解决了我的问题,但我无法理解如何使其适用于我的用例

https://github.com/dominik791/obj-traverse

5 个答案:

答案 0 :(得分:7)

使用DFS。

import React from 'react'
import {Field, FieldArray, reduxForm} from 'redux-form'
import validate from './validate'

const renderField = ({input, label, type, meta: {touched, error}}) => (
  <div>
    <label>{label}</label>
    <div>
      <input {...input} type={type} placeholder={label} />
      {touched && error && <span>{error}</span>}
    </div>
  </div>
)

const renderHobbies = ({fields, meta: {error}}) => (
  <ul>
    <li>
      <button type="button" onClick={() => fields.push()}>Add Hobby</button>
    </li>
    {fields.map((hobby, index) => (
      <li key={index}>
        <button
          type="button"
          title="Remove Hobby"
          onClick={() => fields.remove(index)}
        />
        <Field
          name={hobby}
          type="text"
          component={renderField}
          label={`Hobby #${index + 1}`}
        />
      </li>
    ))}
    {error && <li className="error">{error}</li>}
  </ul>
)

const renderMembers = ({fields, meta: {error, submitFailed}}) => (
  <ul>
    <li>
      <button type="button" onClick={() => fields.push({})}>Add Member</button>
      {submitFailed && error && <span>{error}</span>}
    </li>
    {fields.map((member, index) => (
      <li key={index}>
        <button
          type="button"
          title="Remove Member"
          onClick={() => fields.remove(index)}
        />
        <h4>Member #{index + 1}</h4>
        <Field
          name={`${member}.firstName`}
          type="text"
          component={renderField}
          label="First Name"
        />
        <Field
          name={`${member}.lastName`}
          type="text"
          component={renderField}
          label="Last Name"
        />
        <FieldArray name={`${member}.hobbies`} component={renderHobbies} />
      </li>
    ))}
  </ul>
)

const FieldArraysForm = props => {
  const {handleSubmit, pristine, reset, submitting} = props
  return (
    <form onSubmit={handleSubmit}>
      <Field
        name="clubName"
        type="text"
        component={renderField}
        label="Club Name"
      />
      <FieldArray name="members" component={renderMembers} />
      <div>
        <button type="submit" disabled={submitting}>Submit</button>
        <button type="button" disabled={pristine || submitting} onClick={reset}>
          Clear Values
        </button>
      </div>
    </form>
  )
}

export default reduxForm({
  form: 'fieldArrays', // a unique identifier for this form
})(FieldArraysForm)

答案 1 :(得分:1)

也许这有帮助

menuItems.map(item => {
    if (item.id === 10) return item;
});

BTW我没有考虑这个解决方案的效率。

答案 2 :(得分:1)

我会这样做

		const menuItems = [
			{
				id: 1,
				imageUrl: "http://placehold.it/65x65",
				display: "Shop Women",
				link: "#",
				type: "image",
				nextItems: [
					{
						id: 10,
						display: "홈",
						link: "#",
						type: "menuitem"
					},
					{
						id: 20,
						display: "의류",
						link: "#",
						type: "menuitem-withmore",
						nextItems: [
							{
								id: 100,
								display: "I'm inside one nest",
								link: "#",
								type: "menuitem"
							}
						]
					},
					{
						id: 30,
						display: "가방",
						link: "#",
						type: "menuitem-withmore",
						nextItems: []
					},
					{
						id: 40,
						display: "신발",
						link: "#",
						type: "menuitem-withmore",
						nextItems: []
					},
					{
						id: 50,
						display: "악세서리",
						link: "#",
						type: "menuitem-withmore",
						nextItems: []
					},
					{
						id: 60,
						display: "SALE",
						link: "#",
						type: "menuitem-withmore",
						style: "bold",
						nextItems: []
					},
					{
						id: 70,
						display: "브랜드",
						link: "#",
						type: "menuitem-withmore",
						nextItems: []
					},
					{
						type: "separator"
					},
					{
						id: 80,
						display: "위시리스트",
						link: "#",
						type: "menuitem"
					},
					{
						id: 90,
						display: "고객센터",
						link: "#",
						type: "menuitem"
					},
					{
						id: 99,
						display: "앱 다운로드",
						link: "#",
						type: "menuitem"
					}
				]
			},
			{
				id: 2,
				imageUrl: "http://placehold.it/65x65",
				display: "Shop Men",
				link: "#",
				type: "image",
				nextItems: [
					{
						id: 95,
						display: "MEN's ITEMS.",
						link: "#",
						type: "menuitem"
					}
				]
			}
		];

		var data = [];

		menuItems.forEach(function(item) {
			item.nextItems.forEach(function(element) {
				data.push(element)
			}, this);
		}, this);
    
	console.log(_.where(data, {id: 20}));
<script src="https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.8.3/underscore-min.js"></script>

答案 3 :(得分:1)

您可以尝试使用此功能,它将随着深度变化而动态工作

function findNodeById(nodes, id, callback?) {
  let res;

  function findNode(nodes, id) {

    for (let i = 0; i < nodes.length; i++) {
      if (nodes[i].id === id) {
        res = nodes[i];
        // you can also use callback back here for more optioins ;)
        // callback(nodes[i]);
        break;
      }
      if (nodes[i].nextItems) {
        findNode(nodes[i].nextItems, id);
      }
    }
  }

  findNode(nodes, id)

  return res;
}

findNodeById(menuItems, 99) // { id: 99, display: "앱 다운로드", link: "#", type: "menuitem" }

答案 4 :(得分:-3)

如果你正在使用lodash,你只需要 .find(collection,[predicate = .identity])。
所以你想要这样的东西:

const menuItems = [
    {
        id: 1,
        imageUrl: "http://placehold.it/65x65",
        display: "Shop Women",
        link: "#",
        type: "image",
        nextItems: [
            {
                id: 10,
                display: "홈",
                link: "#",
                type: "menuitem"
            },
            {
                id: 20,
                display: "의류",
                link: "#",
                type: "menuitem-withmore",
                nextItems: [
                    {
                        id: 100,
                        display: "I'm inside one nest",
                        link: "#",
                        type: "menuitem"
                    }
                ]
            },
            {
                id: 30,
                display: "가방",
                link: "#",
                type: "menuitem-withmore",
                nextItems: []
            },
            {
                id: 40,
                display: "신발",
                link: "#",
                type: "menuitem-withmore",
                nextItems: []
            },
            {
                id: 50,
                display: "악세서리",
                link: "#",
                type: "menuitem-withmore",
                nextItems: []
            },
            {
                id: 60,
                display: "SALE",
                link: "#",
                type: "menuitem-withmore",
                style: "bold",
                nextItems: []
            },
            {
                id: 70,
                display: "브랜드",
                link: "#",
                type: "menuitem-withmore",
                nextItems: []
            },
            {
                type: "separator"
            },
            {
                id: 80,
                display: "위시리스트",
                link: "#",
                type: "menuitem"
            },
            {
                id: 90,
                display: "고객센터",
                link: "#",
                type: "menuitem"
            },
            {
                id: 99,
                display: "앱 다운로드",
                link: "#",
                type: "menuitem"
            }
        ]
    },
    {
        id: 2,
        imageUrl: "http://placehold.it/65x65",
        display: "Shop Men",
        link: "#",
        type: "image",
        nextItems: [
            {
                id: 95,
                display: "MEN's ITEMS.",
                link: "#",
                type: "menuitem"
            }
        ]
    }
];

function dfs(obj, targetId) {
  if (obj.id === targetId) {
    return obj
  }
  if (obj.nextItems) {
    for (let item of obj.nextItems) {
      let check = dfs(item, targetId)
      if (check) {
        return check
      }
    }
  }
  return null
}

let result = null

for (let obj of menuItems) {
  result = dfs(obj, 100)
  if (result) {
    break
  }
}

console.dir(result)