我正在使用第三方API,允许我搜索住房属性。遗憾的是,API不是以允许我搜索范围的方式编写的,因此我必须为范围内的每个值单独调用。
因此,如果我想搜索所有有2或3间卧室的房屋,我必须打电话给2间卧室,然后另外打3间卧室。现在这可能变得非常棘手,因为有多个字段可以包含一系列数字(卧室,浴室,地板,车库大小......)。
我的强力JavaScript解决方案是创建一个嵌套的for循环,它将创建一个包含所有调用的数组。这不是一个可扩展的解决方案,我正在寻找一种动态创建for循环的方法或另一种获取所有调用数组的替代方法。
我目前的解决方案:
const searchParams = {
minBedrooms: 2,
maxBedrooms: 4,
minBathrooms: 1,
maxBathrooms: 3,
minFloors: 1,
maxFloors: 1
};
let promises = [];
for (let bedrooms = searchParams.minBedrooms; bedrooms <= searchParams.maxBedrooms; bedrooms++) {
for (let bathrooms = searchParams.minBathrooms; bathrooms <= searchParams.maxBathrooms; bathrooms++) {
for (let floors = searchParams.minFloors; floors <= searchParams.maxFloors; floors++) {
promises.push(callApi(bedrooms, bathrooms, floors));
}
}
}
Promise.all(promises).then(response => {
// do stuff with response
}
此外,用户可能未指定其中一个搜索参数(即 - 卧室数)。因此,API不会应用该特定过滤器。我的代码当前将失败,没有传入卧室值,并且为每个for循环写入条件语句不是我的愿望。
关于如何动态生成上述嵌套for循环的任何想法?
修改
如果用户未指定卧室数量但指定浴室/楼层,我的当前解决方案将失败,因为循环的初始化将无法运行。我不想使用条件语句和许多嵌套循环来创建我的promise数组。这就是为什么我觉得我需要使用动态生成的for循环。
答案 0 :(得分:6)
查看此内容的一种方法称为笛卡尔积[{1}} - 适用于A × B × C
中的a
和A
中的b
以及{{1}在B
中,您需要一个元组c
。
例如C
有4个结果元组:(a, b, c)
,{1, 2} × {3, 4}
,(1, 3)
,(1, 4)
。
最简单的方法是从第一组中的选项开始:(2, 3)
和(2, 4)
。然后,对于第二组中的每个选项,使用新值完成每个元组:
(1)
,添加了(2)
的{{1}}获取(1)
和(2)
3
,添加了(1, 3)
的{{1}}获取(2, 3)
和(1)
在代码中,这可能如下所示:
(2)
以4
结尾,如
(1, 4)
答案 1 :(得分:1)
与Curtis F的答案类似,您可以使用类似
的内容 self.global_settings_frame = wx.Frame(parent=self, title="Global Settings", name="Global Settings")
self.global_settings_listbook = wx.Listbook(parent=self.global_settings_frame, style=wx.LB_LEFT)
self.global_settings_file_window = wx.Panel(parent=self.global_settings_listbook)
self.global_settings_file_box = wx.BoxSizer(orient=wx.VERTICAL)
self.show_full_pathname_checkbox = wx.CheckBox(self.global_settings_file_window, label="Show full pathname")
self.global_settings_file_box.Add(self.show_full_pathname_checkbox, proportion=1)
self.global_default_extension = wx.TextCtrl(self.global_settings_file_window)
self.global_settings_file_box.Add(self.global_default_extension, proportion=1)
self.global_settings_token_window = wx.Panel(parent=self.global_settings_listbook)
self.global_settings_listbook.InsertPage(0, self.global_settings_file_window, "Files")
self.global_settings_listbook.InsertPage(1, self.global_settings_token_window, "Token Defnition")
self.global_settings_frame.Show()
然后以类似的方式构建“元组”,除了for self.global_settings_frame = wx.Frame(parent=self, title="Global Settings", name="Global Settings")
self.global_settings_listbook = wx.Listbook(parent=self.global_settings_frame, style=wx.LB_LEFT)
self.global_settings_file_window = wx.Panel(parent=self.global_settings_listbook)
self.global_settings_file_box = wx.BoxSizer(orient=wx.VERTICAL)
self.show_full_pathname_checkbox = wx.CheckBox(self.global_settings_file_window, label="Show full pathname")
self.global_settings_file_box.Add(self.show_full_pathname_checkbox, proportion=1)
self.global_default_extension = wx.TextCtrl(self.global_settings_file_window)
self.global_settings_file_box.Add(self.global_default_extension, proportion=1)
self.global_settings_token_window = wx.Panel(parent=self.global_settings_listbook)
self.global_settings_listbook.InsertPage(0, self.global_settings_file_window, "Files")
self.global_settings_listbook.InsertPage(1, self.global_settings_token_window, "Token Defnition")
self.global_settings_frame.Show()
中每个对象的for循环需要从const properties = {
"bedrooms": {min: 2, max: 3},
"bathrooms": {min: 1, max: 2},
"floors": {min: 1, max: 4},
}
计算到min
。
答案 2 :(得分:0)
使用递归调用。
请尝试以下代码:
{
function Looping ( parameters, fn, args = [] ) {
if ( parameters.length ) {
let [ [ key, param ], ...pass ] = parameters;
let promises = [];
for ( let i = param.min; i <= param.max; i++ ) {
promises.push( ...Looping( pass, fn, [ ...args, i ] ) );
}
return promises;
}
else {
return [ fn( ...args ) ];
}
}
const searchParams = {
Bedrooms: { min: 2, max: 4 },
Bathrooms: { min: 1, max: 3 },
Floors: { min: 1, max: 1 }
};
function callApi ( a, b, c ) { return Promise.resolve( `Bed: ${a}, Bath: ${b}, Floor: ${c}` ); }
console.time( 'Recursive' );
Promise.all( Looping( Object.entries( searchParams ), ( bedrooms, bathrooms, floors ) => callApi( bedrooms, bathrooms, floors ) ) )
.then( a => {
console.timeEnd( 'Recursive' );
console.log( a );
} );
}
递归调用类型比映射更快。
( async () => {
await new Promise( resolve => {
console.time( 'map' );
function mm ( a, b ) { let r = []; for ( let i = a; i <= b; i++ ) r.push( i ); return r; }
const properties = {
Bedrooms: mm( 1, 100 ),
Bathrooms: mm( 1, 100 ),
Floors: mm( 1, 100 )
};
// Start with a single "empty" tuple
let tuples = [{}]
for (let p in properties) {
// For each property, augment all of the old tuples
let nextTuples = []
for (let option of properties[p]) {
// with each possible option
nextTuples = nextTuples.concat(tuples.map(old => ({[p]: option, ...old})))
}
tuples = nextTuples;
}
let promises = [];
function callApi ( a, b, c ) { return Promise.resolve( `Bed: ${a}, Bath: ${b}, Floor: ${c}` ); }
for ( const i of tuples ) {
let arg = [];
for ( const [ k, v ] of Object.entries( i ) ) {
arg.push( v );
}
promises.push( callApi( ...arg ) );
}
Promise.all( promises ).then( a => {
console.timeEnd( 'map' );
//console.log( a );
resolve();
} );
} );
await new Promise( resolve => {
function Looping ( parameters, fn, args = [] ) {
if ( parameters.length ) {
let [ [ key, param ], ...pass ] = parameters;
let promises = [];
for ( let i = param.min; i <= param.max; i++ ) {
promises.push( ...Looping( pass, fn, [ ...args, i ] ) );
}
return promises;
}
else {
return [ fn( ...args ) ];
}
}
const searchParams = {
Bedrooms: { min: 1, max: 100 },
Bathrooms: { min: 1, max: 100 },
Floors: { min: 1, max: 100 }
};
function callApi ( a, b, c ) { return Promise.resolve( `Bed: ${a}, Bath: ${b}, Floor: ${c}` ); }
console.time( 'Recursive' );
Promise.all( Looping( Object.entries( searchParams ), ( bedrooms, bathrooms, floors ) => callApi( bedrooms, bathrooms, floors ) ) )
.then( a => {
console.timeEnd( 'Recursive' );
//console.log( a );
resolve();
} );
} );
} )();
答案 3 :(得分:0)
您可以使用的一种方法是递归函数,其中每个图层将迭代矩阵的一个维度:
const dims = [
{ min: 2, max: 4 },
{ min: 1, max: 3 },
{ min: 1, max: 1 },
];
function matrix(dims, ...args) {
const dim = dims[0];
return dims.length
? [...new Array(dim.max - dim.min + 1)]
.map((_,i) => i + dim.min)
.map(x => matrix(dims.slice(1), ...args, x))
.reduce((a, b) => [...a, ...b], [])
: [callApi(...args)];
}
function callApi(bedrooms, bathrooms, floors) {
return `bedrooms: ${bedrooms}, bathrooms: ${bathrooms}, floors: ${floors}`;
}
console.log(matrix(dims));
&#13;
答案 4 :(得分:0)
这不是一个答案,只需比较PO和最佳答案之间的表现。
我认为OP的代码足够好,只需要确保所有最大/最小值都有默认值。
我假设一个建筑有180层,最多5间卧室,最多5间浴室。
然后发现简单的三个嵌套循环(OP&#39; s解决方案)要快得多。
const searchParams = {
minBedrooms: 1,
maxBedrooms: 5,
minBathrooms: 0,
maxBathrooms: 5,
minFloors: 1,
maxFloors: 180
};
console.time("OP's")
let promises = [];
for (let bedrooms = searchParams.minBedrooms; bedrooms <= searchParams.maxBedrooms; bedrooms++) {
for (let bathrooms = searchParams.minBathrooms; bathrooms <= searchParams.maxBathrooms; bathrooms++) {
for (let floors = searchParams.minFloors; floors <= searchParams.maxFloors; floors++) {
promises.push([bedrooms, bathrooms, floors]);
}
}
}
console.timeEnd("OP's")
const properties = {
"bedrooms": [1, 2, 3, 4, 5],
"bathrooms": [0, 1, 2, 3, 4, 5],
"floors": Array.from(new Array(180).keys()),
}
console.time('Best Answer')
// Start with a single "empty" tuple
let tuples = [{}]
for (let p in properties) {
// For each property, augment all of the old tuples
let nextTuples = []
for (let option of properties[p]) {
// with each possible option
nextTuples = nextTuples.concat(tuples.map(old => ({[p]: option, ...old})))
}
tuples = nextTuples;
}
console.timeEnd('Best Answer')
&#13;