独特的日期数组Javascript

Jor*_*tad 8 javascript arrays date

我看到这个问题经常被问到常规的javascript数组,但是如果有一个日期数组,那么答案似乎都无法解决.

我可以通过试验错误地解决这个问题,但如果我问的话,我确实看到了其他人的一些好处.

基本上如果你有一个javascript数组的日期可能有重复,需要过滤到一个没有重复的数组,最好的方法是什么?

我尝试过ES6解决方案,Array.from(new Set(arr))但它只返回相同的数组.

我也试过了

Array.prototype.unique = function() {
    var a = [];
    for (var i=0, l=this.length; i<l; i++)
        if (a.indexOf(this[i]) === -1)
            a.push(this[i]);
    return a;
}
Run Code Online (Sandbox Code Playgroud)

两者都来自数组中的唯一值

但是没有工作,看起来像是indexOf在日期对象上不起作用.

这是我的数组生成atm的方式

//this is an array generated from ajax data, 
//its a year over year comparison with a separate year, 
//so to create a reliable date objects I force it to use the same year.
data.map(d => {
   dp = new Date(Date.parse(d.date + '-' + d.year));
   dp.setFullYear(2000);
   return dp;
})
Run Code Online (Sandbox Code Playgroud)

它大约有100个左右不同的日子,但它总是以350左右的指数结束.

Ser*_*kiy 11

ES6 道路:

datesArray.filter((date, i, self) => 
  self.findIndex(d => d.getTime() === date.getTime()) === i
)
Run Code Online (Sandbox Code Playgroud)

感谢/sf/answers/2572131271/


Tim*_*imo 10

如果比较两个日期===,则比较两个日期对象的引用.表示相同日期的两个对象仍然是不同的对象.

相反,比较以下时间戳Date.prototype.getTime():

function isDateInArray(needle, haystack) {
  for (var i = 0; i < haystack.length; i++) {
    if (needle.getTime() === haystack[i].getTime()) {
      return true;
    }
  }
  return false;
}

var dates = [
  new Date('October 1, 2016 12:00:00 GMT+0000'),
  new Date('October 2, 2016 12:00:00 GMT+0000'),
  new Date('October 3, 2016 12:00:00 GMT+0000'),
  new Date('October 2, 2016 12:00:00 GMT+0000')
];

var uniqueDates = [];
for (var i = 0; i < dates.length; i++) {
  if (!isDateInArray(dates[i], uniqueDates)) {
    uniqueDates.push(dates[i]);
  }
}

console.log(uniqueDates);
Run Code Online (Sandbox Code Playgroud)

优化和错误处理取决于您.


VLA*_*LAZ 5

您可以使用查找做一个简单的过滤器,但是您需要将日期转换为可以比较的内容,因为JavaScript中两个对象永远都不相同,除非它是对相同对象的两个引用。

const dates = [
  new Date(2016, 09, 30, 10, 35, 40, 0),
  new Date(2016, 09, 30, 10, 35, 40, 0), //same
  new Date(2016, 09, 30, 10, 35, 40, 0), //same
  new Date(1995, 07, 15, 03, 15, 05, 0) //different
];


function filterUniqueDates(data) {
  const lookup = new Set();
  
  return data.filter(date => {
     const serialised = date.getTime();
    if (lookup.has(serialised)) {
      return false;
    } else { 
      lookup.add(serialised);
      return true;
    }
  })
}

console.log(filterUniqueDates(dates));
Run Code Online (Sandbox Code Playgroud)

如果您只想更改确定唯一性的方式来过滤任何内容,则可以进一步概括

const dates = [
  new Date(2016, 09, 30, 10, 35, 40, 0),
  new Date(2016, 09, 30, 10, 35, 40, 0), //same
  new Date(2016, 09, 30, 10, 35, 40, 0), //same
  new Date(1995, 07, 15, 03, 15, 05, 0) //different
];

const dateSerialisation = date => date.getTime(); // this is the previous logic for dates, but extracted

//as primitives, these can be compared for uniqueness without anything extra
const numbers = [1, 2, 2, 3, 3, 3, 4, 4, 4, 4];
const strings = ["a", "b", "b", "c", "c", "c"];

const people = [
  {name: "Alice", age: 20},
  {name: "Bob", age: 30},
  {name: "Bob", age: 40}, //technically the same
  {name: "Carol", age: 50},
  {name: "Carol", age: 60}, //technically the same
  {name: "Carol", age: 70} //technically the same
]

//let's assume that a person with the same name is the same person regardless of anything else 
const peopleSerialisation = person => person.name;

/* 
 * this now accepts a transformation function that will be used 
 * to find duplicates. The default is an identity function that simply returns the same item.
 */
function filterUnique(data, canonicalize = x => x) { 
  const lookup = new Set();
  
  return data.filter(item => {
     const serialised = canonicalize(item); //use extract the value by which items are considered unique
    
    if (lookup.has(serialised)) {
      return false;
    } else { 
      lookup.add(serialised);
      return true;
    }
  })
}


console.log("dates", filterUnique(dates, dateSerialisation));
console.log("numbers", filterUnique(numbers));
console.log("strings", filterUnique(strings));
console.log("people", filterUnique(people, peopleSerialisation));
Run Code Online (Sandbox Code Playgroud)

这使用的是ES6,但转换为符合ES5的代码很简单-删除粗箭头功能,默认参数,new Set()这就是您需要的:

function filterUnique(data, canonicalize) {
  if (!canonicalize) {
    canonicalize = function(x) { return x; }
  }

  var lookup = {};

  return data.filter(function(item) {
     var serialised = canonicalize(item);

    if (lookup.hasOwnProperty(serialised)) {
      return false;
    } else { 
      lookup[serialised] = true;
      return true;
    }
  })
}
Run Code Online (Sandbox Code Playgroud)