线组合算法
Line combination algorithm
array = [[1, 2], [13, 14], [4, 5], [80, 30], [12, 14], [10, 90], [3, 2], [6, 9], [1, 5], [4, 5], [5, 9], [4, 3], [13, 12]]
//expected
output = [[1, 2], [13, 14], [4, 5], [80, 30], [10, 90], [3, 2], [6, 9], [4, 5], [5, 9], [4, 3], [13, 12]]
你可以把子数组看成线,例如,[1,2]
是一条从点1连接到点2的线。因此,[1,2],[3,2],[4,3],[4,5],[4,3]
将与连接点1的几条短线相关联到5点,因为1点到2点、2点到3点、3点到4点、4点到5点都有一条线连接。
如果数组包含较大的单行,即点 1 到点 5,则应将其过滤掉。这是为了删除所有较长的线,这些线已经在更短的线中定义了它们的点。可以使用什么算法来解决这个问题?
我已经在 https://codepen.io/Maximusssssu/pen/jOYXrNd?editors=0012
尝试了下面的代码
第一部分以升序输出所有子数组以提高可读性,而对于第二部分,我尝试了 include()
方法来检查子数组中是否存在节点,并获取其位置。
array = [[1, 2], [13, 14], [4, 5], [80, 30], [12, 14], [10, 90], [3, 2], [6, 9], [1, 5], [4, 5], [5, 9], [4, 3], [13, 12]]
array_ascending_arr = [];
for (let i = 0; i < array.length; i++) {
let subarrayy = array[i].sort(function(a, b) {
return a - b
});
array_ascending_arr.push(subarrayy);
}
console.log(array_ascending_arr) // output all subarrays in ascending order back into array
for (let k = 1; k < 5; k++) {
for (let m = 0; m < array.length; m++) {
for (let i = 1; i < 2; i++) {
if (array_ascending_arr[m].includes(k) == true) {
console.log(m)
}
}
}
console.log(".......")
}
你可以试试邻接表。我对该算法的理解是,如果两对共享一条边,它们将组合形成一条新边,直到所有集合都是唯一的。
主要思想是计算中间元素数量的差异而不是价值
如果我们有 [[1,2],[14,10],[4,6],[9,2]
使得序列 = [1,2,4,6,9,10,14]
(已排序)
return 增量值:
[1,2] -> d:1
[9,2] -> d:3 // the 9 is three positions away from the 2
因此原则是从最远的值开始处理到最远的值
(其他排序条件是次要的,主要用于调试)
注意:重复对也被剔除
const
test1 = [[1,2],[13,14],[4,5],[80,30],[12,14],[10,90],[3,2],[6,9],[1,5],[4,5],[5,9],[4,3],[13,12]]
, test2 = [[1,2],[4,5],[30,80],[12,18],[10,90],[2,3],[6,9],[1,5],[4,6],[5,9],[3,4],[12,13],[12,14],[14,15],[15,18]]
;
console.log('test1:\n', JSON.stringify( combination( test1 )))
console.log('test2:\n', JSON.stringify( combination( test2 )))
function combination(arr)
{
let
nodes = arr.flat().sort((a,b)=>a-b).filter((c,i,{[i-1]:p})=>(c!==p))
, sets = nodes.map(g=>[g])
, bads = []
;
arr // i:index, s:start(min), e:end(max), d: delta
.map(([v0,v1],i) => ({i,s:Math.min(v0,v1),e:Math.max(v0,v1), d:Math.abs(nodes.indexOf(v0) - nodes.indexOf(v1))}))
.sort((a,b) => (a.d-b.d) || (a.s-b.s) || (a.e-b.e) || (a.i-b.i) )
.forEach(({i,s,e,d}) =>
{
let
gS = sets.find(n=>n.includes(s))
, gE = sets.find(n=>n.includes(e))
;
if (gS === gE) { bads.push(i) }
else { gS.push(...gE); gE.length=0 }
})
//console.log( sets.filter(a=>a.length).map(a=>JSON.stringify(a)).join(' - ') )
return arr.filter((x,i)=>!bads.includes(i))
}
.as-console-wrapper { max-height: 100% !important; top: 0; }
.as-console-row::after { display: none !important; }
因此,据我了解,您正在尝试删除范围大于范围小于范围的任何数字集。以下代码应执行此操作:
array.filter(pair => {
// Get the smaller and larger numbers from the pair
const [small, big] = pair.sort((a,b) => a-b)
// Check if this pair is larger than any others
return !array.some(test => {
const [testSmall, testBig] = test.sort((a,b) => a-b)
return big > testBig && small < testSmall
})
})
请注意,这不会删除重复项。
如果您不介意子数组在最终数组中重新排序,您可以通过在开头对它们进行排序来稍微简化它:
array
.map(pair => pair.sort((a,b) => a-b))
.filter(([s, b], _, arr) => !arr.some(([ts, tb]) => b>tb && s<ts))
array = [[1, 2], [13, 14], [4, 5], [80, 30], [12, 14], [10, 90], [3, 2], [6, 9], [1, 5], [4, 5], [5, 9], [4, 3], [13, 12]]
//expected
output = [[1, 2], [13, 14], [4, 5], [80, 30], [10, 90], [3, 2], [6, 9], [4, 5], [5, 9], [4, 3], [13, 12]]
你可以把子数组看成线,例如,[1,2]
是一条从点1连接到点2的线。因此,[1,2],[3,2],[4,3],[4,5],[4,3]
将与连接点1的几条短线相关联到5点,因为1点到2点、2点到3点、3点到4点、4点到5点都有一条线连接。
如果数组包含较大的单行,即点 1 到点 5,则应将其过滤掉。这是为了删除所有较长的线,这些线已经在更短的线中定义了它们的点。可以使用什么算法来解决这个问题?
我已经在 https://codepen.io/Maximusssssu/pen/jOYXrNd?editors=0012
尝试了下面的代码第一部分以升序输出所有子数组以提高可读性,而对于第二部分,我尝试了 include()
方法来检查子数组中是否存在节点,并获取其位置。
array = [[1, 2], [13, 14], [4, 5], [80, 30], [12, 14], [10, 90], [3, 2], [6, 9], [1, 5], [4, 5], [5, 9], [4, 3], [13, 12]]
array_ascending_arr = [];
for (let i = 0; i < array.length; i++) {
let subarrayy = array[i].sort(function(a, b) {
return a - b
});
array_ascending_arr.push(subarrayy);
}
console.log(array_ascending_arr) // output all subarrays in ascending order back into array
for (let k = 1; k < 5; k++) {
for (let m = 0; m < array.length; m++) {
for (let i = 1; i < 2; i++) {
if (array_ascending_arr[m].includes(k) == true) {
console.log(m)
}
}
}
console.log(".......")
}
你可以试试邻接表。我对该算法的理解是,如果两对共享一条边,它们将组合形成一条新边,直到所有集合都是唯一的。
主要思想是计算中间元素数量的差异而不是价值
如果我们有 [[1,2],[14,10],[4,6],[9,2]
使得序列 = [1,2,4,6,9,10,14]
(已排序)
return 增量值:
[1,2] -> d:1
[9,2] -> d:3 // the 9 is three positions away from the 2
因此原则是从最远的值开始处理到最远的值
(其他排序条件是次要的,主要用于调试)
注意:重复对也被剔除
const
test1 = [[1,2],[13,14],[4,5],[80,30],[12,14],[10,90],[3,2],[6,9],[1,5],[4,5],[5,9],[4,3],[13,12]]
, test2 = [[1,2],[4,5],[30,80],[12,18],[10,90],[2,3],[6,9],[1,5],[4,6],[5,9],[3,4],[12,13],[12,14],[14,15],[15,18]]
;
console.log('test1:\n', JSON.stringify( combination( test1 )))
console.log('test2:\n', JSON.stringify( combination( test2 )))
function combination(arr)
{
let
nodes = arr.flat().sort((a,b)=>a-b).filter((c,i,{[i-1]:p})=>(c!==p))
, sets = nodes.map(g=>[g])
, bads = []
;
arr // i:index, s:start(min), e:end(max), d: delta
.map(([v0,v1],i) => ({i,s:Math.min(v0,v1),e:Math.max(v0,v1), d:Math.abs(nodes.indexOf(v0) - nodes.indexOf(v1))}))
.sort((a,b) => (a.d-b.d) || (a.s-b.s) || (a.e-b.e) || (a.i-b.i) )
.forEach(({i,s,e,d}) =>
{
let
gS = sets.find(n=>n.includes(s))
, gE = sets.find(n=>n.includes(e))
;
if (gS === gE) { bads.push(i) }
else { gS.push(...gE); gE.length=0 }
})
//console.log( sets.filter(a=>a.length).map(a=>JSON.stringify(a)).join(' - ') )
return arr.filter((x,i)=>!bads.includes(i))
}
.as-console-wrapper { max-height: 100% !important; top: 0; }
.as-console-row::after { display: none !important; }
因此,据我了解,您正在尝试删除范围大于范围小于范围的任何数字集。以下代码应执行此操作:
array.filter(pair => {
// Get the smaller and larger numbers from the pair
const [small, big] = pair.sort((a,b) => a-b)
// Check if this pair is larger than any others
return !array.some(test => {
const [testSmall, testBig] = test.sort((a,b) => a-b)
return big > testBig && small < testSmall
})
})
请注意,这不会删除重复项。
如果您不介意子数组在最终数组中重新排序,您可以通过在开头对它们进行排序来稍微简化它:
array
.map(pair => pair.sort((a,b) => a-b))
.filter(([s, b], _, arr) => !arr.some(([ts, tb]) => b>tb && s<ts))