Javascript Array Distinct (array.reduce实现)

JS去重技巧
本文介绍JavaScript中实现数组去重的方法,包括使用双重for循环检查重复元素的传统方式,以及利用对象索引提高效率的技巧,并展示了如何通过reduce方法将去重功能添加到Array原型中。

javascript 没有原生的Distinct功能 . (至少现在还没有)
但我们可以通过简单的script 自己实现 . 
Distinct就是把数组中重复出现2次或以上的值给删除掉,确保数组内每个值都是唯一的 . 
我相信大家开始的时候都会和我用同一个方法来处理。
那就是开一个新的数组(空),然后 for loop 旧的数组 ,然后复制进去新的数组里面,每次复制进去的时候先检查一篇新数组内是否有了这个值,有了就跳过,没有才加进去 。 
代码 :
  var old_array = [1, 2, 3, 3, 4, 5]; //3重复了
            var new_array = [];
            for (var i = 0; i < old_array.length; i++) {
                var value = old_array[i];
                var is_exist = false;
                for (var j = 0; j < new_array.length; j++) { 
                    if (new_array[j] === old_array[i]) { //检查
                        is_exist = true;
                        break;
                    }
                }
                if (is_exist) continue;//跳过
                new_array.push(old_array[i]); //添加
            }
            alert(new_array); //[1,2,3,4,5]

有些人可能觉得这样效率不太好,因为for loop 很多次匹配 .
有人就建议使用 object 来替代 
代码 : 
  var u = {}, a = [];
        for (var i = 0, l = this.length; i < l; ++i) {
            if (u.hasOwnProperty(this[i])) {
                continue;
            }
            a.push(this[i]);
            u[this[i]] = 1;
        }
        return a;
object 走索引,似乎可以快一些,但是这里有个小问题。
就是如果你的数组中有 object ,这样就会造成错误了。(ECMA6好像不会了)
因为object 的属性不能是 object ,只能是 string 和 number .
所以不鼓励使用这个方法,除非你确保你的数组内的值都是 string , number . 
总结 : 
方法1的文言文写法是这样的 : 
代码 :
  var old_array = [1, 2, 3, 3, 4, 5]; //3重复了
            old_array = old_array.reduce(function (new_array, old_array_value) {
                if (new_array.indexOf(old_array_value) == -1) new_array.push(old_array_value);
                return new_array; //最终返回的是 prev value 也就是recorder
            }, []);

最后把它加入 array的 prototype里面就可以啦 
代码 : 
 Array.prototype.distinct = function () {
        return this.reduce(function (new_array, old_array_value) {
            if (new_array.indexOf(old_array_value) == -1) new_array.push(old_array_value);
            return new_array; //最终返回的是 prev value 也就是recorder
        }, []);
    }
调用 :
var old_array = [1, 2, 3, 3, 4, 5]; //3重复了
var new_array = old_array.distinct();

这里顺便提一下 reduce 方法

function(prev,now,index,array) { return prev; }

当index=0时,prev就是我们第一次传入reduce方法的第2个参数 (reduce(fn, 这个值 <--))

接着循环时 now 就是 array 内的值 

每次return的值是下一次循环的 prev 值 , 所以最后我们得到的就是prev. 

 

转载于:https://www.cnblogs.com/keatkeat/p/3896549.html

”// ====== 1. 加载研究区域和采样点数据 ====== var aoi = ee.FeatureCollection('projects/ee-yixuwei610/assets/hubei'); var samplePoints = ee.FeatureCollection('projects/ee-yixuwei610/assets/sample_points'); // 替换为您的采样点路径 var geometry = aoi.geometry(); Map.centerObject(geometry, 8); Map.addLayer(geometry, {color: 'red'}, 'Hubei AOI'); Map.addLayer(samplePoints, {color: 'blue'}, '采样点'); // ====== 2. 加载和处理Sentinel-2影像集 ====== var startYear = 2023; // 物候分析的年份 var startDate = ee.Date.fromYMD(startYear, 1, 1); var endDate = ee.Date.fromYMD(startYear, 12, 31); // NDVI计算函数[^4][^5] var calculateNDVI = function(image) { var ndvi = image.normalizedDifference(['B8', 'B4']).rename('NDVI'); return image.addBands(ndvi); }; // 云掩膜函数 var cloudMask = function(image) { var qa = image.select('QA60'); var cloudBitMask = 1 << 10; var cirrusBitMask = 1 << 11; var mask = qa.bitwiseAnd(cloudBitMask).eq(0) .and(qa.bitwiseAnd(cirrusBitMask).eq(0)); return image.updateMask(mask); }; // 加载Sentinel-2数据 var s2Collection = ee.ImageCollection('COPERNICUS/S2_SR') .filterBounds(geometry) .filterDate(startDate, endDate) .map(cloudMask) .map(calculateNDVI) .select('NDVI'); // ====== 3. Savitzky-Golay滤波函数[^2] ====== var applySGFilter = function(collection) { return collection.map(function(image) { // 创建周围5天的滑动窗口 var window = collection.filter(ee.Filter.inList('system:time_start', ee.List([image.get('system:time_start')]) .map(function(t) { return ee.Date(t).advance(-2, 'day').millis(); }, ee.List.sequence(-2, 2)) .flatten() )); // 应用二次多项式拟合 var sgFiltered = window.reduce(ee.Reducer.mean()); return sgFiltered.copyProperties(image, ['system:time_start']); }); }; var filteredCollection = applySGFilter(s2Collection); // ====== 4. 创建物候曲线面板组件 ====== var mainPanel = ui.Panel({ style: { position: 'bottom-right', width: '450px', padding: '10px', backgroundColor: '#f8f9fa' } }); var title = ui.Label({ value: `${startYear}年采样点物候特征曲线`, style: {fontSize: '18px', fontWeight: 'bold', margin: '0 0 10px 0'} }); mainPanel.add(title); var pointSelector = ui.Select({ items: [], placeholder: '选择采样点', style: {width: '100%', margin: '0 0 10px 0'} }); mainPanel.add(pointSelector); var chartPanel = ui.Panel({ style: {height: '300px', backgroundColor: 'white'} }); mainPanel.add(chartPanel); var phenoParams = ui.Label({ value: '等待选择采样点...', style: {margin: '10px 0 0 0', fontSize: '14px'} }); mainPanel.add(phenoParams); Map.add(mainPanel); // ====== 5. 初始化采样点列表 ====== var pointNames = samplePoints.aggregate_array('name').distinct(); pointNames.evaluate(function(names) { names.forEach(function(name) { pointSelector.items().push(name, name); }); }); // ====== 6. 时间序列拟合与物候参数计算 ====== pointSelector.onChange(function(selectedName) { var selectedPoint = samplePoints.filter(ee.Filter.eq('name', selectedName)).first(); var pointGeometry = selectedPoint.geometry(); Map.centerObject(pointGeometry, 12); Map.layers().reset([Map.layers().get(0), Map.layers().get(1)]); Map.addLayer(pointGeometry, {color: 'red', pointSize: 10}, '选中点'); // 提取原始NDVI时间序列 var rawTS = s2Collection.map(function(image) { var value = image.reduceRegion({ reducer: ee.Reducer.mean(), geometry: pointGeometry, scale: 10 }).get('NDVI'); return ee.Feature(null, { date: image.date().format('YYYY-MM-dd'), NDVI: ee.Number(value), timestamp: image.get('system:time_start'), type: '原始值' }); }); // 提取滤波后NDVI时间序列 var filteredTS = filteredCollection.map(function(image) { var value = image.reduceRegion({ reducer: ee.Reducer.mean(), geometry: pointGeometry, scale: 10 }).get('NDVI'); return ee.Feature(null, { date: image.date().format('YYYY-MM-dd'), NDVI: ee.Number(value), timestamp: image.get('system:time_start'), type: 'S-G滤波' }); }); // 合并两个时间序列 var combinedTS = rawTS.merge(filteredTS); // 创建双线图表 var chart = ui.Chart.feature.groups({ features: combinedTS, xProperty: 'timestamp', yProperty: 'NDVI', seriesProperty: 'type' }) .setChartType('LineChart') .setOptions({ title: `${selectedName} - ${startYear}年物候曲线`, hAxis: {title: '日期', format: 'MMM', gridlines: {count: 12}}, vAxis: {title: 'NDVI', minValue: -0.2, maxValue: 1.0}, lineWidth: 2, pointSize: 3, series: { 0: {color: '#4CAF50', lineWidth: 1, pointSize: 3}, // 原始值 1: {color: '#FF5722', lineWidth: 3, pointSize: 0} // S-G滤波 }, curveType: 'function' }); // 更新图表 chartPanel.widgets().reset([chart]); // 计算关键物候参数(基于滤波后数据) var phenoStats = filteredTS.aggregate_array('NDVI') .map(function(ndvi) { return ee.Number(ndvi); }); var minNDVI = phenoStats.reduce(ee.Reducer.min()); var maxNDVI = phenoStats.reduce(ee.Reducer.max()); var amplitude = maxNDVI.subtract(minNDVI); // 计算生长季开始日期(阈值法)[^1] var sosFeature = filteredTS.filter(ee.Filter.gt('NDVI', 0.3)) .limit(1, 'timestamp', false) .first(); // 更新物候参数显示 sosFeature.get('date').evaluate(function(date) { phenoParams.setValue( `NDVI振幅: ${amplitude.getInfo().toFixed(3)}\n` + `生长季开始: ${date}\n` + `NDVI峰值: ${maxNDVI.getInfo().toFixed(3)}` ); }); }); // 初始选择第一个点 if (pointSelector.items().length > 0) { pointSelector.setValue(pointSelector.items().get(0).value); } “显示所有采样点的物候特征曲线
最新发布
09-01
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值