javascript - Verificarea dacă elementele dintr-un array mapat împărtășesc valori


Construiesc un feed de știri folosind React și moment.js. Folosind .map redau elemente cu un titlu și conținut. Aș dori să verific dacă un element a fost postat în același an și lună ca alt element. Dacă acesta este cazul, vreau să ascund titlul celui de-al doilea element.

Vă rog să vedeți exemplul meu

În prezent, codul meu redă asta:

Martie 2018

știre unu

Martie 2018

știre doi

Septembrie 2017

știrea trei

iunie 2017

știre patru

Deoarece elementele unu și doi împărtășesc aceeași lună și același an, aș dori să le prezint în felul următor:

Martie 2018

știre unu

știre doi

Septembrie 2017

știrea trei

iunie 2017

știrea patru

Pe baza acestui răspuns, am încercat să găsesc noduri cu nume de clase duplicate, dar nu am ajuns exact acolo:

let monthNodes = [...document.querySelectorAll('.months')];
let months = []

monthNodes.map(month => {
 months.push(month.className) 
})

const count = names => 
names.reduce((a, b) => 
Object.assign(a, {[b]: (a[b] || 0) + 1}), {})

const duplicates = dict => 
Object.keys(dict).filter((a) => dict[a] > 1)

console.log(count(months)) // {March_2018: 2, December_2017: 1, November_2017: 1}
console.log(duplicates(count(months))) // [ 'March_2018' ]

Poate că abordez greșit această problemă și folosirea .map în primul rând este o idee proastă?

Actualizare

Mulțumesc pentru toate răspunsurile grozave, a fost greu să aleg între ele deoarece toate funcționează bine. Trebuie să accept răspunsul lui David Ibl, deoarece el a fost primul care a oferit un exemplu funcțional.

Răspuns #1

Array.prototype.reduce() poate fi utilizat pentru a organiza Articles sub formă de Object după year și month.

Vezi mai jos pentru un exemplu practic.

JSFiddle

// News
class News extends React.Component {

  // State.
  state = {  
    news: [ 
        {content: 'news item one -- march 2018', date: '2018-03-02'},
        {content: 'news item two -- march 2018', date: '2018-03-17'},
        {content: 'news item two -- sep 2017', date: '2017-09-21'},
        {content: 'news item one -- june 2017', date: '2017-06-15'}
    ]
  }
  
  // Render.
  render = () => (
    <div>
      {
        Object.entries(this.organised()).map(([yearmonth, articles], i) => (
          <div key={i}>
            <h3>{yearmonth}</h3>
            {articles.map((article, j) => (
              <div key={j}>
                {article.content}
              </div>
            ))}
          </div>
        ))
      }
    </div>
  )
  
  // Organised.
  organised = () => this.state.news.reduce((total, article) => {
    const key = moment(article.date).format('YYYY MMMM')
    return {
      ...total,
      [key]: total[key] && total[key].concat(article) || [article]
    }
  }, {})
}

// Mount.
ReactDOM.render(<News/>,document.getElementById('container'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.21.0/moment.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="container"></div>

Răspunsul #2

poți să o faci în felul următor: https://jsfiddle.net/2e27jvvh/

render() {
const arr = new Array();
return( 
    <div>
    {this.state.news.map(item => {
        const yearMonth = moment(item.date).format("MMMM YYYY");
        const yearM = moment(item.date).format("MMMM_YYYY");
        if (arr.indexOf(yearMonth) < 0){
            arr.push(yearMonth);
          return (
          <div className={'months ' + yearM}>
              <h2>{yearMonth}</h2>
              <p>{item.content}</p> 
          </div>
            ) 
        } else {
            return (
          <div className={'months ' + yearM}>
              <p>{item.content}</p> 
          </div>
            ) 
        }

        }) 
    }
 </div>
)
}

Poate ar trebui să sortezi elementele în funcție de an și lună înainte pentru a asigura un comportament corect chiar și atunci când elementele nu sunt sortate inițial. Dar asta funcționează cu exemplul tău.