我想知道从数组中获取最大元素的最佳方法是什么。
例如,我的区域具有温度:
let regions = [{name: 'alabama', temp: 20}, {name: 'newyork', temp: 30}...];
可以一行完成,但我想表现出色。
我只想遍历数组一次。
如果一个以上的区域具有相同的最高温度,我想全部获取
与带有临时变量的过程代码相比,您知道一种使代码更紧凑的方法吗?
如果可以通过“函数式编程”方式完成,那就太好了。
这是示例过程代码:
regions = [{name:'asd', temp: 13},{name: 'fdg', temp: 30}, {name: 'asdsd', temp: 30}]
maxes = []
max = 0
for (let reg of regions) {
if (reg.temp > max) {
maxes = [reg];
max = reg.temp
} else if (reg.temp == max) {
maxes.push(reg)
} else {
maxes =[]
}
}
答案 0 :(得分:2)
使用R.pipe
temp
的值temp
)将配对减少为一对。
const { pipe, groupBy, prop, toPairs, reduce, maxBy, head, last } = R;
const regions = [
{name: 'california', temp: 30},
{name: 'alabama', temp: 20},
{name: 'newyork', temp: 30}
];
const result = pipe(
groupBy(prop('temp')),
toPairs,
reduce(maxBy(pipe(head, Number)), [-Infinity]),
last
)(regions);
console.log(result);
<script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.25.0/ramda.js"></script>
答案 1 :(得分:2)
另一种Ramda方法:
const {reduce, append} = R
const regions = [{name:'asd', temp: 13},{name: 'fdg', temp: 30}, {name: 'asdsd', temp: 30}]
const maxTemps = reduce(
(tops, curr) => curr.temp > tops[0].temp ? [curr] : curr.temp === tops[0].temp ? append(curr, tops) : tops,
[{temp: -Infinity}]
)
console.log(maxTemps(regions))
<script src="//cdnjs.cloudflare.com/ajax/libs/ramda/0.25.0/ramda.js"></script>
此版本仅迭代列表一次。但这有点难看。
除非测试表明性能是我的应用程序中的问题,否则我通常更喜欢Ori Drori的版本。即使使用我的评论中的修复程序,我也认为代码比此代码更易于理解。 (如果只有两种情况,那就不是真的。(例如<
与>=
。)但是,当存在三种情况时,这很难看懂,但是我们可以对其进行格式化。>
但是如果性能确实是一个主要问题,那么您的原始代码也可能比此代码要快。
答案 2 :(得分:2)
一种不同的处理方法(虽然稍微冗长一些)是创建一些帮助程序来一般地负责折叠事物列表以提取最大值列表。
我们可以通过定义一个Semigroup包装类(也可以是一个普通函数而不是一个类)来做到这一点。
const MaxManyBy = fn => class MaxMany {
constructor(values) {
this.values = values
}
concat(other) {
const otherValue = fn(other.values[0]),
thisValue = fn(this.values[0])
return otherValue > thisValue ? other
: otherValue < thisValue ? this
: new MaxMany(this.values.concat(other.values))
}
static of(x) {
return new MaxMany([x])
}
}
此类的主要目的是能够通过比较其中包含的值来合并两个列表,并且每个列表都包含相同的可比较值。
我们现在可以引入一个新的辅助函数,该函数将一些函数应用于列表的每个值,然后使用concat
将它们组合在一起。
const foldMap = (fn, [x, ...xs]) =>
xs.reduce((acc, next) => acc.concat(fn(next)), fn(x))
有了这些帮助器,我们现在可以创建一个函数来从示例中获取最高温度。
const maxTemps = xs =>
foldMap(MaxManyBy(({temp}) => temp).of, xs).values
maxTemps([
{name: 'california', temp: 30},
{name: 'alabama', temp: 20},
{name: 'newyork', temp: 30}
])
//=> [{"name": "california", "temp": 30}, {"name": "newyork", "temp": 30}]
这里假设传递给foldMap
的列表是非空的。如果您可能会遇到一个空列表,那么您将需要进行相应的修改以返回某种默认值(如果没有默认值,则将其包装为Maybe
类型)。
请参阅下面的完整代码段。
const MaxManyBy = fn => class MaxMany {
constructor(values) {
this.values = values
}
concat(other) {
const otherValue = fn(other.values[0]),
thisValue = fn(this.values[0])
return otherValue > thisValue ? other
: otherValue < thisValue ? this
: new MaxMany(this.values.concat(other.values))
}
static of(x) {
return new MaxMany([x])
}
}
const foldMap = (fn, [x, ...xs]) =>
xs.reduce((acc, next) => acc.concat(fn(next)), fn(x))
const maxTemps = xs =>
foldMap(MaxManyBy(({temp}) => temp).of, xs).values
const regions = [
{name: 'california', temp: 30},
{name: 'alabama', temp: 20},
{name: 'newyork', temp: 30}
]
console.log(maxTemps(regions))