javascript: encontrar la diferencia entre elementos específicos en una matriz

CorePress2024-01-24  12

Tengo un objeto de datos similar a este:

 const data = [
  {
      name: "john smith", created_at: "1616846400", description: "clocked in" //7am
  },
  {
    name: "john smith", created_at: "1616853600", description: "clocked Out" //9am
  },
  {
    name: "john smith", created_at: "1616857200", description: "clocked in" //10am
  },
  {
    name: "john smith", created_at: "1616875200", description: "clocked out" //3pm
  }
];

Esto pretende representar una hoja perforada de entrada y salida. El objetivo es encontrar el tiempo total que esta persona ha estado fichada durante un turno de trabajo.

la respuesta sería 1 hora. El usuario había registrado su salida a las 9 a.m. y regresó a las 10 a.m. y ya no fue registrado hasta que se fue por el día.

He intentado esto de diferentes maneras, mi intento más reciente fue así

const data = [
  {
      name: "john smith", created_at: "1616846400", description: "clocked in"
  },
  {
    name: "john smith", created_at: "1616853600", description: "clocked Out"
  },
  {
    name: "john smith", created_at: "1616857200", description: "clocked in"
  },
  {
    name: "john smith", created_at: "1616875200", description: "clocked Out"
  }
];


let clockOuts = data.filter(function (e) {
    return e.description.split(" ").splice(0,2).join(" ") ===  "clocked Out"
  })

  let clockIns = data.filter(function (e) {
    return e.description.split(" ").splice(0,2).join(" ") ===  "clocked in"
  })


  var x = clockOuts.map(function(item, index) {

    if (clockIns[index] != null) {
      return Math.round(Math.abs(item.created_at - clockIns[index].created_at) / 60)
    } else {

      return Math.round(Math.abs(item.created_at * 0))
    }
  })//end clockins Map

  
  console.log(x)

  var sum = x.reduce(function(a, b){
    return a + b
  }, 0)

  console.log(sum)

¡Cualquier ayuda sería apreciada ya que me he topado con un muro!



------------------------------------

moment.js te ayudará mucho:

const data = [
  {name: "john smith", created_at: "1616846400", description:"clocked in"},
  {name: "john smith", created_at: "1616853600", description:"clocked Out"},
  {name: "john smith", created_at: "1616857200", description: "clocked in"},
  {name: "john smith", created_at: "1616875200", description: "clocked out"}
];

let clockedOutTimes = data.reduce((r,i,ix,o)=>{
   if (ix===0 || ix === o.length-1) return r;
   if (i.description.toLowerCase()==='clocked in') {
      let d = moment.unix(parseInt(i.created_at))
        .diff(moment.unix(parseInt(o[ix-1].created_at)),'hours');
      r=r+d
   }
   return r;
},0);

console.log(clockedOutTimes);
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.29.1/moment.min.js"></script>



------------------------------------

Primero, debe asegurarse de que todos los elementos estén en una secuencia; de lo contrario, nada funcionará. Por eso necesitas agrupar los elementos.

Para hacer eso, convierto los datos originales a una nueva matriz. Los campos de identificación son solo para ver el resultado fácilmente, por lo que no forman parte de ninguna funcionalidad.

El objetivo aquí es eliminar los elementos con ID 3 y 6 porque están rompiendo la secuencia.

const data = [
  { id: 1, name: 'john smith', created_at: '1616846400', description: 'clocked in' },
  { id: 2, name: 'john smith', created_at: '1616853600', description: 'clocked Out' },
  { id: 3, name: 'john smith', created_at: '1616857200', description: 'clocked in' },
  { id: 4, name: 'john smith', created_at: '1616867200', description: 'clocked in' },
  { id: 5, name: 'john smith', created_at: '1616875200', description: 'clocked Out' },
  { id: 6, name: 'john smith', created_at: '1616875200', description: 'clocked Out' },
  { id: 7, name: 'john smith', created_at: '1616867200', description: 'clocked in' },
  { id: 8, name: 'john smith', created_at: '1616875200', description: 'clocked Out' },
];


let sequence = {
  'clocked in': 'clocked Out',
  'clocked Out': 'clocked in',
};

let sequentialData = [];

const convertTime = x => {
  return Math.round(Math.abs(x[1].created_at - x[0].created_at) / 60)
}

for (let i = 0; i < data.length; i++) {
  if (
    data[i].description != 'clocked in' ||
    data[i + 1]?.description != sequence[data[i].description]
  ) {
    continue;
  }
  let pair = [data[i], data[i + 1]];
  sequentialData.push([convertTime(pair), ...pair]);
}

console.log(sequentialData)

2

¡Gracias por la respuesta! Si no es mucha molestia, ¿podrías explicar la funcionalidad de esta línea? datos[i + 1]?.descripción != secuencia[datos[i].descripción] ¡Estoy tratando de absorber tanto conocimiento/comprensión como sea posible!

Griffith9601

27/03/2021 a las 20:20

Está comparando las descripciones de los elementos actuales y siguientes. Digamos que si la descripción del elemento actual es ''cloc"marcada", la secuencia ["marcada"] será "marcada" y si la descripción del siguiente elemento está "marcada como salida" pueden crear un par como dentro y fuera. De lo contrario, debemos pasar al siguiente índice.

-Bulent

27/03/2021 a las 20:25



------------------------------------

Creo que podrías hacer algo como esto:

let clockOutDuration = 0

for (let i = 0; i < data.length; i++) {
    const item = data[i]
    const nextItem = i < data.length - 1 ? data[i + 1] : null
    
    // clock out with clock in after
    if (item.description === 'clocked Out' && nextItem && nextItem.description === 'clocked in') {
        clockOutDuration += parseInt(nextItem.created_at) - parseInt(item.created_at)
    }
}

y luego, asumiendo que el tiempo creado_en está en milisegundos, puedes convertir a tu unidad de tiempo preferida.

Math.floor(clockOutDuration/1000) para segundos, Math.floor(clockOutDuration/1000/60) para minutos, etc.

Respondido

27 de marzo de 2021 a las 19:10

Jonny

Jonny

1

Su guía para un futuro mejor - libreflare
Su guía para un futuro mejor - libreflare