繁体   English   中英

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

[英]Best way to search for repeated values in a Multidimensional array in javascript

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

我有一个包含多个 arrays 的多维数组“团队”,这些数组具有以下格式的 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]
]

由于某种原因,先前的数据以任意顺序排列。

我想要做的是查看多维数组“团队”内部,其中 WL 记录在相邻的 arrays 中是相同的。 从之前的数据来看,B队、C、D队和E队的WL记录相同,而且都是相邻的。 F 队不一样,因为虽然它与 W 匹配,但与 L 不匹配。请注意,H 队具有相同的 20-7 记录,但由于它不相邻,我们不考虑它来进行比较!

现在我想通过 sort_key 按 ASC 顺序重新组织相邻的团队 B、C、D 和 E。 与另一个阵列没有匹配 WL 的 arrays 必须保持在同一个 position 中。 因此,解决方案将如下所示:

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
]

注意:前面的示例有相邻的 arrays 具有相同的 WL 20-7,但可能有更多的“块”与匹配 WL arrays 彼此相邻,这可能会发生多次,直到我们到达 Z47576 FE07FDD492ADBE0DE 处的数组.

我的想法是:

  1. 取第一个数组并与下一个数组进行比较,如果有 WL 匹配则检查下一个,n 次直到没有进一步匹配。 如果没有匹配,我们继续下一个数组并再次执行此步骤。

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

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

  4. 我们继续寻找更多这样的匹配,直到我们到达 position 'n',我们可以退出并返回最终正确排序的 Teams 数组。

它似乎并不那么复杂,但我无法弄清楚如何将多维 arrays 与两个匹配值(WL)进行比较......请帮助:)

您正在请求组内的三级排序。 使用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((ab) => { 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>' );

你可以写一个通用的groupAdjacent function。 它有两个参数 -

  1. t - 输入数组
  2. equal - 一个 function 来测试元素是否被认为是相邻的
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)

相关阅读


等价

Scott 指出.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)

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

使用groupWith ,编写我们的主要 function 非常简单,只需使用 function 调用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}

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

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

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 函数。


注 1这最初使用and而不是both 我目前不确定为什么这会奏效,并将进行调查。 感谢用户感谢您的关注!

尝试这个。

逻辑。

  1. 弹出前面,直到 pivot 元件的 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)


暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM