在 javascript 中的多维数组中搜索重复值的最佳方法



在Javascript中解决以下问题的最佳方法是什么? 我试图解决它,但我遇到了太多麻烦,甚至不值得发布我当前的代码,这是一个丑陋的混乱。

我有一个多维数组"团队",其中包含多个数组,这些数组具有以下格式的TeamName(字符串),WinRecord(数字),LossRecord(数字)和Sort_Key(数字):[TeamName,W,L,sort_key]

我的数据如下所示:

Teams = [
['Team A', 25, 2, 88],
['Team B', 20, 7, 84],
['Team C', 20, 7, 76],
['Team D', 20, 7, 54],
['Team E', 20, 7, 65],
['Team F', 20, 6, 34],
['Team G', 19, 8, 67],
['Team H', 20, 7, 11],
...
['Team N', 3, 24, 33]
]

由于某种原因,前面的数据是任意顺序的。

我想做的是查看多维数组"团队"内部,其中 W-L 记录在相邻数组中是相同的。从之前的数据来看,B、C、D和E队的W-L记录相同,而且它们都彼此相邻。F队没有相同的记录,因为虽然它与W匹配,但它与L不匹配.请注意,H队具有相同的20胜7负的战绩,但由于它不相邻,我们不考虑将其用于比较!

现在我想按 sort_key 的 ASC 顺序重新组织相邻的团队 B、C、D 和 E。 没有与另一个数组匹配的 W-L 的数组必须保持在同一位置。 因此,解决方案将如下所示:

Teams = [
['Team A', 25, 2, 88], //stays in the same place because it has no W-L match adjacent
['Team D', 20, 7, 54],    //sort_key is the lowest of this "chunk" so this goes first
['Team E', 20, 7, 65],    //sort_key second in ASC order  
['Team C', 20, 7, 76],    //then this one
['Team B', 20, 7, 84],    //finally this is the highest sort_key of this "chunk"
['Team F', 20, 6, 34], //stays in the same place because it has no W-L match adjacent
['Team G', 19, 8, 67], //stays in the same place because it has no W-L match adjacent
['Team H', 20, 7, 11], //stays in the same place because its NOT ADJACENT to the last 20-7 team
...
['Team N', 3, 24, 33] //stays in the same place because it has no W-L match adjacent
]

注意:前面的例子具有具有相同 W-L 的相邻数组 20-7 ,但可能有更多的"块"与彼此相邻的匹配 W-L 数组,这可能会发生多次,直到我们到达位置"n"的数组。

我想到的是:

  1. 要获取第一个数组并与下一个数组进行比较,如果有 W-L 匹配项来检查下一个数组,则 n 次,直到没有进一步的匹配。如果没有匹配项,我们转到下一个数组并再次执行此步骤。

  2. 如果存在相邻的 W-L,我们需要继续检查下一个数组,直到没有完全匹配并停止。所有相邻的匹配数组都可以复制到临时数组中。我们需要"从"original_position保存,因为如果我们从 Teams[2] 一直到 Teams[5] 中的数据,我们需要稍后从位置 2 开始重新插入排序的值。也许将此original_position保存到变量中?

  3. 我们现在按 ASC 对临时数组进行排序sort_key。我们现在将临时数组"从"original_position复制到原始 Teams 数组中。

  4. 我们
  5. 一直在寻找更多这样的比赛,直到我们到达位置"n",我们可以退出并返回最终正确排序的 Teams 数组。

它似乎并不那么复杂,但我无法弄清楚如何比较具有两个匹配值 (W-L) 的多维数组......请帮忙:)

您可以编写泛型groupAdjacent函数。它有两个参数 -

  1. t- 输入数组
  2. equal- 用于测试元素是否被视为相邻元素的函数
function groupAdjacent(t, equal)
{ function* run (r, q, i)
{ if (i >= t.length)
return yield [...r, q]
if (equal(q, t[i]))
return yield* run([...r, q], t[i], i + 1)
yield [...r, q]
yield* run([], t[i], i + 1)
}
return t.length
? Array.from(run([], t[0], 1))
: [] 
}

接下来,我们定义两个特定于您的特定teams数据的函数 -

  1. teamAdjacent- 确定使团队邻接的原因
  2. teamSort- 比较两个团队进行排序
const teamAdjacent = (a, b) =>
a[1] == b[1] && a[2] == b[2] // w/l is equal
const teamSort = (a, b) =>
a[3] - b[3]                  // sort by sortKey, ascending

最后,我们将所有东西联系在一起。groupAdjacent创建一个组数组,然后我们.sort每个组,最后调用.flat返回一个未分组的result-

const result =
groupAdjacent(teams, teamAdjacent)
.map(_ => _.sort(teamSort))
.flat()
console.log(result)
['Team A', 25, 2, 88]
['Team D', 20, 7, 54]
['Team E', 20, 7, 65]
['Team C', 20, 7, 76]
['Team B', 20, 7, 84]
['Team F', 20, 6, 34]
['Team G', 19, 8, 67]
['Team H', 20, 7, 11]
['Team N', 3, 24, 33]

展开代码段以在您自己的浏览器中验证结果 -

function groupAdjacent(t, equal)
{ function* run (r, q, i)
{ if (i >= t.length)
return yield [...r, q]
if (equal(q, t[i]))
return yield* run([...r, q], t[i], i + 1)
yield [...r, q]
yield* run([], t[i], i + 1)
}
return t.length
? Array.from(run([], t[0], 1))
: [] 
}
const teamAdjacent = (a, b) =>
a[1] == b[1] && a[2] == b[2] // w/l is equal
const teamSort = (a, b) =>
a[3] - b[3]                  // sort by sortKey, ascending
const teams =
[ ['Team A', 25, 2, 88]
, ['Team B', 20, 7, 84]
, ['Team C', 20, 7, 76]
, ['Team D', 20, 7, 54]
, ['Team E', 20, 7, 65]
, ['Team F', 20, 6, 34]
, ['Team G', 19, 8, 67]
, ['Team H', 20, 7, 11]
, ['Team N', 3, 24, 33]
]
const result =
groupAdjacent(teams, teamAdjacent)
.map(_ => _.sort(teamSort))
.flat()
console.log(result)


如果你愿意,你也可以在没有递归的情况下编写groupAdjacent-

function* groupAdjacent(t, equal)
{ if (t.length === 0) return
let g = [t[0]]
for (const _ of t.slice(1))
if (equal(_, g[0]))
g.push(_)
else
(yield g, g = [_])
yield g
}

与此版本的唯一区别是您必须将groupAdjacent调用包装在Array.from-

const result =
Array.from(groupAdjacent(teams, teamAdjacent))
.map(_ => _.sort(teamSort))
.flat()
// => (same output)
<小时 />

相关阅读

  • Javascript:对数组中的对象组进行洗牌
  • 如何使用 javascript 对间接数组进行排序?
  • 在函数式编程中,我应该如何根据不同的条件对具有不同逻辑的对象内部的列表进行排序?
<小时 />

等效

斯科特指出,.map(fn).flat()的使用与.flatMap(fn)1相同。我应该注意到这一点,因为我认为我从来没有使用过.flat这是另一种没有必要的情况——

const result =
groupAdjacent(teams, teamAdjacent)
.map(_ => _.sort(teamSort))
.flat()

相当于 -

const result =
groupAdjacent(teams, teamAdjacent)
.flatMap(_ => _.sort(teamSort))

1.仅在展平深度为1时等效,即.flat().flat(1)

您正在请求组中的三级排序。 使用array.sort(comparator-function).

.map用于调整数据结构,以便按 4 级排序;计算组、赢、输、关键。第二个.map将恢复为原始数据结构。

例:

var Teams = [
['Team A', 25, 2, 88],
['Team B', 20, 7, 84],
['Team C', 20, 7, 76],
['Team D', 20, 7, 54],
['Team E', 20, 7, 65],
['Team F', 20, 6, 34],
['Team G', 19, 8, 67],
['Team H', 20, 7, 11],
['Team N',  3, 24, 33]
];
var group = 0;

Teams =
Teams
.map((item,index) => {

if ( (index > 0)  
&&
( item[1] != Teams[index-1][1]  // wins different
||
item[2] != Teams[index-1][2]  // losses different
)
) group++;  // adjacency group

return { item: item, group: group }  
})
.sort((a,b) => {
const d0 = a.group - b.group // computed group ascending
// const d1 = b.item[1] - a.item[1];  // wins   (accounted for in group)
// const d2 = b.item[2] - a.item[2];  // losses (accounted for in group)
const d3 = a.item[3] - b.item[3];  // key ascending
// return (d0 != 0) ? d0 : (d1 != 0) ? d1 : (d2 != 0) ? d2 : d3;
return (d0 != 0) ? d0 : d3;
})
.map(item => item.item)
;
document.write ('<PRE>' + 
Teams
.reduce ( 
(html, item) => html + JSON.stringify(item) + "n"
, ""
) + '</PRE>'
);

我倾向于通过Ramda的思想来思考这些问题。 (免责声明:我是它的主要作者之一。 Ramda 有一个函数groupWith,它完成此的基本工作,将连续匹配的元素分组到子数组中,基于测试两个连续值是否应该组合在一起的函数。 它的一次性版本使用两个简单的辅助函数,也受到Ramda的启发,last,它获取数组的最后一个元素和init,它获取除最后一个元素之外的所有元素。

使用groupWith,编写我们的 main 函数非常简单,只需使用测试输赢是否匹配的函数调用groupWith,然后按sort_key对各个组进行排序并将结果展平化回单个数组。

它可能看起来像这样:

// utility functions
const last = (xs = []) =>
xs [xs.length - 1]
const init = (xs = []) =>
xs .slice (0, -1)
const groupWith = (match) => (xs) => 
xs.reduce (
(xss, x, i) => i > 0 && match (x, last (last (xss)))
? [...init (xss), [...last (xss), x]]
: [...xss, [x]],
[]
)


// main function
const process = (xs) => 
groupWith ((a, b) => a [1] == b [1] && a [2] == b [2]) (xs) 
.flatMap (x => x .sort ((a, b) => a [3] - b [3])) 

// sample data
const teams = [['Team A', 25, 2, 88], ['Team B', 20, 7, 84], ['Team C', 20, 7, 76], ['Team D', 20, 7, 54], ['Team E', 20, 7, 65], ['Team F', 20, 6, 34], ['Team G', 19, 8, 67], ['Team H', 20, 7, 11], ['Team N', 3, 24, 33]]

// demo
console .log (process (teams))
.as-console-wrapper {max-height: 100% !important; top: 0}

这在结构上与谢谢的答案相同。 但是代码足够不同,可以单独呈现。

拉出内联在那里的帮助程序函数可能会更干净。 那看起来像:

const groupWL = (a, b) => 
a [1] == b [1] && a [2] == b [2]
const sortByIdx3 = (a, b) => 
a [3] - b [3]
const process = (xs) => 
groupWith (groupWL) (xs) 
.flatMap (x => x .sort (sortByIdx3)) 

或者我们可以将这些帮助程序写为

const groupWL  = ([, w1, l1, ], [, w2, l2, ]) =>
w1 == w2 && l1 == l2
const sortByIdx3 = ([, , , sk1], [, , , sk2]) => 
sk1 - sk2 

最后,为了进行比较,以下是我如何使用Ramda(但请参阅下面的注释1):

const process = pipe (
groupWith (both (eqProps (1), eqProps (2))),
chain (sortBy (nth (3)))
)

其中pipegroupWithbotheqPropschainsortBynth都是Ramda函数。


note 1这最初使用and而不是both。 我目前不确定为什么这甚至有效,并将进行调查。 感谢用户谢谢你注意到它!

试试这个。

逻辑。

  1. 弹出前部,直到枢轴元素的 W/L 不同
  2. 对子数组进行排序并将其合并到结果数组中
  3. 执行 1 和 2,直到原始数组为空

可以添加复制登录,防止原始数组变异,推荐

let teams = [
['Team A', 25, 2, 88], //stays in the same place because it has no W-L match adjacent
['Team D', 20, 7, 54],    //sort_key is the lowest of this "chunk" so this goes first
['Team E', 20, 7, 65],    //sort_key second in ASC order  
['Team C', 20, 7, 76],    //then this one
['Team B', 20, 7, 84],    //finally this is the highest sort_key of this "chunk"
['Team F', 20, 6, 34], //stays in the same place because it has no W-L match adjacent
['Team G', 19, 8, 67], //stays in the same place because it has no W-L match adjacent
['Team H', 20, 7, 11]
]
const groupByWL = (teams) =>{
const pivot = teams[0]
const ret = [ pivot ]
for(i in teams){
if(i == 0) continue
const [ name, W, L ] = teams[i]

if(W != pivot[1] || L != pivot[2] ) break
ret.push(teams[i])
}

ret.sort(function(a, b) {//put your sort logic in here
return a[3] - b[3]
})

return ret
}
const search = teams =>{
let ret = []

while(teams.length){
const chunk = groupByWL(teams)
teams = teams.slice(chunk.length, teams.length)
ret = [ ...ret, ...chunk ]
console.log(teams)
console.log(ret)
}

return ret
}
const result = search(teams)
console.log(teams)

相关内容

  • 没有找到相关文章

最新更新