在遍历两个数组时查找公用值

时间:2019-07-12 13:37:00

标签: javascript arrays

我有一种情况需要比较和查找两个数组的共同值。我很清楚如何做到这一点,但不确定在这种情况下如何做到这一点。

我的第一个数组如下:

[ { kind: 'E',
    path: [ 'short_name' ],
    lhs: 'testing',
    rhs: 'testing1' },
  { kind: 'E',
    path: [ 'agent_name' ],
    lhs: 'testing',
    rhs: 'testing2' } ]

上面的数组代表与文档更改有关的信息。

第二个数组如下:

[ { lhs: 'legacyId', rhs: 'id_number' },
  { lhs: 'name.short', rhs: 'short_name' },
  { lhs: 'name.long', rhs: 'agent_name' },
  { lhs: 'gender', rhs: 'gender' },
  { lhs: 'dob', rhs: 'date_of_birth' } ]

我需要做的是遍历并在第一个数组的元素和第二个数组的“ rhs”值中找到“ path”的通用值。

因此,根据我在此处的示例,我应该最终找到以下值:short_nameagent_name

我如何编写循环以在两个数组上执行此操作?

4 个答案:

答案 0 :(得分:5)

您可以reduce在第一个数组上,并在第二个数组上使用forEach循环,以查看每个值是否相等,然后将值推入累加器:

const arr1 = [{ kind: 'E', path: [ 'short_name' ], lhs: 'testing', rhs: 'testing1' }, { kind: 'E', path: [ 'agent_name' ], lhs: 'testing', rhs: 'testing2' }]
const arr2 = [{ lhs: 'legacyId', rhs: 'id_number' }, { lhs: 'name.short', rhs: 'short_name' }, { lhs: 'name.long', rhs: 'agent_name' }, { lhs: 'gender', rhs: 'gender' }, { lhs: 'dob', rhs: 'date_of_birth' }]

const common = arr1.reduce((a, o1) => {
  const match = arr2.find(o2 => o1.path[0] === o2.rhs)
  match && a.push(match.rhs)
  return a
}, [])

console.log(common)

如果您确实想这样做,可以在一行中使用查找而不是第二个reduce来编写:

const a = [{ kind: 'E', path: [ 'short_name' ], lhs: 'testing', rhs: 'testing1' }, { kind: 'E', path: [ 'agent_name' ], lhs: 'testing', rhs: 'testing2' }]
const b = [{ lhs: 'legacyId', rhs: 'id_number' }, { lhs: 'name.short', rhs: 'short_name' }, { lhs: 'name.long', rhs: 'agent_name' }, { lhs: 'gender', rhs: 'gender' }, { lhs: 'dob', rhs: 'date_of_birth' }]

const common = a.reduce((a, o1) => [...a, b.find(o2 => o1.path[0] === o2.rhs).rhs], [])

console.log(common)

或者,为获得更高效的解决方案;),您可以使用一组:

const a = [{ kind: 'E', path: [ 'short_name' ], lhs: 'testing', rhs: 'testing1' }, { kind: 'E', path: [ 'agent_name' ], lhs: 'testing', rhs: 'testing2' }]
const b = [{ lhs: 'legacyId', rhs: 'id_number' }, { lhs: 'name.short', rhs: 'short_name' }, { lhs: 'name.long', rhs: 'agent_name' }, { lhs: 'gender', rhs: 'gender' }, { lhs: 'dob', rhs: 'date_of_birth' }]
var commonValues = []
var set = new Set([])

for (let i = 0; i < a.length; i++) { 
  const value = a[i].path[0]
  if (!set.has(value)) set.add(value)
}
for (let i = 0; i < b.length; i++) {
  const val = b[i].rhs
  if (set.has(val)) commonValues.push(val)
}

console.log(commonValues)

答案 1 :(得分:2)

您可以在for ...

中使用简单的for

这是最简单的方法(也许不是最高性能的方法),从第一个数组获取值,然后循环第二个数组。如果找到一个值,则将其推入另一个数组(results)并中断第二个循环(如果值已匹配,则无需继续运行)。

var a = [ { kind: 'E',
    path: [ 'short_name' ],
    lhs: 'testing',
    rhs: 'testing1' },
  { kind: 'E',
    path: [ 'agent_name' ],
    lhs: 'testing',
    rhs: 'testing2' } ]


var b =[ { lhs: 'legacyId', rhs: 'id_number' },
  { lhs: 'name.short', rhs: 'short_name' },
  { lhs: 'name.long', rhs: 'agent_name' },
  { lhs: 'gender', rhs: 'gender' },
  { lhs: 'dob', rhs: 'date_of_birth' } ]
  
var results = [];  
for (var i = 0; i < a.length; i++){
  var path = a[i].path;
  
  for (var j = 0; j < b.length; j++){
    var rhs = b[j].rhs;
    if (rhs == path){
      results.push(b[j].rhs)
      break;
    }
    
  }
}

console.log(results)

答案 2 :(得分:2)

您可以通过嵌套一个循环并在第二个循环中搜索第一个循环的每个值来在O(n ^ 2)时间内进行操作,也可以使用哈希映射在O(n)时间内进行操作。在JavaScript中,我们为此使用对象,因为可以在O(1)时间内访问它们的值。

示例:

class Recipe: BindableObject {
    var didChange = PassthroughSubject<Void, Never>()
    var currentStep = Step() {
        didSet {
            didChange.send(())
        }
    }
}

struct Parameter: Identifiable {
    var id:Int = 0
    var name = ""
    var minimum:Float = 0
    var maximum:Float = 100
    var `default`:Float = 30
    var current:Float = 30
}

struct StepRow: View {
    @EnvironmentObject var recipe: Recipe
    var step: Step!

    init(step: Step) {
        self.step = step
    }
    var body: some View {
        Button(action: {
            self.setCurrentStep()
        }) {
            HStack {
                Text(step.name).font(Font.body.weight(.bold))
            }.frame(height: 50)
        }
    }
    func setCurrentStep() {
        recipe.currentStep = step
    }
}
struct ParameterRow: View {
    @EnvironmentObject var recipe: Recipe
    @State var sliderValue:Float = 30
    var parameter: Parameter!

    init(parameter: Parameter) {
        self.parameter = parameter
    }

    var body: some View {
        VStack {
            Text(parameter.name)
            Slider(

                // This works, swap these two lines to duplicate the index out of range error by:
                // - Adding step 1, step 2, step 3, and finally step 4
                // - Tapping each step in the step list in order, the first three will work but the last one won't

                //value: $recipe.currentStep.parameters[parameter.id].current,
                value: self.$sliderValue,

                from: parameter.minimum,
                through: parameter.maximum,
                by: 1.0
            )
        }
    }
}
struct ContentView : View {
    @EnvironmentObject var recipe: Recipe
    var body: some View {
        VStack {
            List {
                ForEach(recipe.steps) { step in
                    StepRow(step: step)
                }
            }
            List {
                ForEach(recipe.currentStep.parameters) { parameter in
                    ParameterRow(parameter: parameter)
                }
            }
        }
    }
}

虽然看起来似乎要编写更多代码,但是通过这种方式使数据任意大,可以节省大量的时间复杂性。假设您的数据长100项,已经有O(n ^ 2)个解决方案需要10,000次通过才能找到所有匹配项。与上述解决方案相反,它将需要200次通过。随着您的数据变大,这些节省的时间会迅速增加。

答案 3 :(得分:2)

从第二个数组的Set值中提取一个rhs,并通过检查集合来减少第一个数组和过滤器路径

const arr1= [ { kind: 'E',
    path: [ 'short_name' ],
    lhs: 'testing',
    rhs: 'testing1' },
  { kind: 'E',
    path: [ 'agent_name' ],
    lhs: 'testing',
    rhs: 'testing2' } ],
    
    arr2= [ { lhs: 'legacyId', rhs: 'id_number' },
  { lhs: 'name.short', rhs: 'short_name' },
  { lhs: 'name.long', rhs: 'agent_name' },
  { lhs: 'gender', rhs: 'gender' },
  { lhs: 'dob', rhs: 'date_of_birth' } ],
  
  arr2Set = new Set(arr2.map(({rhs}) => rhs)),
  matches = arr1.reduce((a,{path}) =>[...a, ...path.filter(p => arr2Set.has(p))],[]);
  
  
  console.log(matches)