Related
I have a "format" array that's used in a map function to return an array of objects with start and end dates.
This format array contains the group of dates that belong to the same object.
let format = [3, 3, 1, 5, 4, 4, 3, 5, 13, 10, 3, 5, 5, 2, 2, 10];
So this way we know the first 3 dates same group, next 3 dates, same group, next date single group date, etc.
My issue/problem: is when there's a group of dates with no-lineal dates (for example 05, 06, 12, 13).
With my actual function, is returning an object with
Start: 05
End: 13
But this isn't correct, because we are counting all the days in the middle between 5 and 13. What I would like to do would create two objects for this case:
{
"start": 05,
"end": 06
},
{
"start": 12,
"end": 13
}
In my code, you can see this behavior with the last group of dates (10) (last object).
Is there any way to "check" for the range-dates" before creating the object? Should I add a .map inside the current .map to get 3 sets from the last 10
{
"2022-01-05T04:00:00.000Z", // start
"2022-01-06T04:00:00.000Z",
"2022-01-07T04:00:00.000Z" // end
},
{
"2022-01-10T04:00:00.000Z", // start
"2022-01-11T04:00:00.000Z",
"2022-01-12T04:00:00.000Z",
"2022-01-13T04:00:00.000Z",
"2022-01-14T04:00:00.000Z" // end
},
{
"2022-01-17T04:00:00.000Z", // start
"2022-01-18T04:00:00.000Z" // end
}
Current code:
let format = [3, 3, 1, 5, 4, 4, 3, 5, 13, 10, 3, 5, 5, 2, 2, 10];
let dates = [
"2021-10-04T04:00:00.000Z",
"2021-10-06T04:00:00.000Z",
"2021-10-07T04:00:00.000Z",
"2021-10-13T04:00:00.000Z",
"2021-10-14T04:00:00.000Z",
"2021-10-15T04:00:00.000Z",
"2021-10-15T04:00:00.000Z",
"2021-10-17T22:00:00.000Z",
"2021-10-18T22:00:00.000Z",
"2021-10-19T22:00:00.000Z",
"2021-10-20T22:00:00.000Z",
"2021-10-21T22:00:00.000Z",
"2021-10-17T22:00:00.000Z",
"2021-10-18T22:00:00.000Z",
"2021-10-19T22:00:00.000Z",
"2021-10-20T22:00:00.000Z",
"2021-10-19T04:00:00.000Z",
"2021-10-20T04:00:00.000Z",
"2021-10-21T04:00:00.000Z",
"2021-10-22T04:00:00.000Z",
"2021-10-19T04:00:00.000Z",
"2021-10-20T04:00:00.000Z",
"2021-10-21T04:00:00.000Z",
"2021-10-25T04:00:00.000Z",
"2021-10-26T04:00:00.000Z",
"2021-10-27T04:00:00.000Z",
"2021-10-28T04:00:00.000Z",
"2021-10-29T04:00:00.000Z",
"2021-10-25T04:00:00.000Z",
"2021-10-26T04:00:00.000Z",
"2021-10-27T04:00:00.000Z",
"2021-10-28T04:00:00.000Z",
"2021-10-29T04:00:00.000Z",
"2021-11-01T04:00:00.000Z",
"2021-11-02T04:00:00.000Z",
"2021-11-03T04:00:00.000Z",
"2021-11-04T04:00:00.000Z",
"2021-11-05T04:00:00.000Z",
"2021-11-08T04:00:00.000Z",
"2021-11-09T04:00:00.000Z",
"2021-11-10T04:00:00.000Z",
"2021-11-01T04:00:00.000Z",
"2021-11-02T04:00:00.000Z",
"2021-11-03T04:00:00.000Z",
"2021-11-04T04:00:00.000Z",
"2021-11-05T04:00:00.000Z",
"2021-11-08T04:00:00.000Z",
"2021-11-09T04:00:00.000Z",
"2021-11-10T04:00:00.000Z",
"2021-11-11T04:00:00.000Z",
"2021-11-12T04:00:00.000Z",
"2021-11-11T04:00:00.000Z",
"2021-11-12T04:00:00.000Z",
"2021-11-13T04:00:00.000Z",
"2021-11-15T04:00:00.000Z",
"2021-11-16T04:00:00.000Z",
"2021-11-17T04:00:00.000Z",
"2021-11-18T04:00:00.000Z",
"2021-11-19T04:00:00.000Z",
"2021-11-16T04:00:00.000Z",
"2021-11-17T04:00:00.000Z",
"2021-11-18T04:00:00.000Z",
"2021-11-19T04:00:00.000Z",
"2021-11-20T04:00:00.000Z",
"2021-11-23T04:00:00.000Z",
"2021-11-24T04:00:00.000Z",
"2021-11-23T04:00:00.000Z",
"2021-11-24T04:00:00.000Z",
"2022-01-05T04:00:00.000Z",
"2022-01-06T04:00:00.000Z",
"2022-01-07T04:00:00.000Z",
"2022-01-10T04:00:00.000Z",
"2022-01-11T04:00:00.000Z",
"2022-01-12T04:00:00.000Z",
"2022-01-13T04:00:00.000Z",
"2022-01-14T04:00:00.000Z",
"2022-01-17T04:00:00.000Z",
"2022-01-18T04:00:00.000Z"
];
const res = format.map(num => {
const arr = dates.splice(0,num)
const start = arr.shift();
const end = arr.length === 0 ? start : arr.pop()
return {
start: start,
end: end
}
})
console.log(res);
I am learning the Mocha test for js but have a weird problem an couldn't figure it out. Any big man can help me:
I do this test case:
it("remove all the number larger than 10", () => {
function filter(arr) {
return arr.filter(number => number < 11);
}
assert.equal(filter([1, 3, 3, 5, 10, 29, 3], [1, 3, 3, 5, 10, 3]));
});
But it returns undefined for that filter function, but when I remove the return keyword, it works fine:
it("remove all the number larger than 10", () => {
function filter(arr) {
arr.filter(number => number < 11);
}
assert.equal(filter([1, 3, 3, 5, 10, 29, 3], [1, 3, 3, 5, 10, 3]));
});
Can anyone can explain it to me?
Thanks
You've got a typo, your close paren ) for filter should be immediately after the first array instead of after both arrays.
Also, to compare arrays use assert.deepEqual instead of assert.equal:
it("remove all the number larger than 10", () => {
function filter(arr) {
return arr.filter(number => number < 11);
}
assert.deepEqual(filter([1, 3, 3, 5, 10, 29, 3]), [1, 3, 3, 5, 10, 3]); // SUCCESS
});
(The reason why it was passing when you removed the return keyword is that filter was being passed both arrays, then returning undefined. assert.equal was only being called with one argument so its second argument was implicitly undefined. Since undefined == undefined your test passed.)
I have been trying to use a node.js script to turn some data into music. The script is only returning a single note for some reason:
The orignal script on github: https://github.com/wbkd/from-data-to-sound had res.concat(scribble.scale('c', but the threw an error Invalid Scale name.
const scribble = require('scribbletune');
// example data
const data = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 10, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1];
const min = Math.min(...data);
const octaves = [...Array(5)].map((d, i) => i + 1); // [1, 2, 3, 4, 5]
// creates array of notes like 'c1', 'd1', 'e1', 'gb1', 'ab1', 'bb1', 'c2', ...
const notes = octaves.reduce((res, octave) =>
res.concat(scribble.scale('c1 major', 'whole tone', octave, false))
, []);
const midiData = scribble.clip({
notes: data.map(value => notes[value - min]),
pattern: 'x',
noteLength: '1/16',
});
// write the MIDI file 🎵🎵🎵
scribble.midi(midiData, 'data-sonification.mid');
From scribbletune doc:
each x implies a note on event
scribbletune docs/core/clip
Since you're passing only 1 'x' as a pattern in scribble.clip, it only plays 1 note. In order for all the notes to be played, you can try something like this:
const midiData = scribble.clip({
notes: data.map(value => notes[value - min]),
- pattern: 'x', // only play 1 note
+ pattern: 'x'.repeat(data.length), // repeat this pattern for each note in data
noteLength: '1/16',
});
I'm trying to accomplish a task with reduce() that I know how to do with forEach(). Unfortunately I'm not sure how to structure the syntax and I can't find a good example.
Example 1) In this code I use forEach() to insert the word species into the first index of each array.
"use strict";
var creatureArray;
creatureArray = [
['zombie', 30, 1, 'bite', 0, 5],
['skeleton', 10, 2, 'sword', 1, 10],
['orc', 15, 4, 'club', 1, 7]
];
creatureArray.forEach(function(value, index, array) {
array[index].unshift('species');
});
console.log(creatureArray);
Example 2) In this code I try to accomplish something similar using .reduce(). However I know that I'm missing a piece of syntax. I can't figure out how to apply the updated array to the accumulator which is then returned as an object. Thanks so much for any help!
"use strict";
var creatureArray, creatureObject;
creatureArray = [
['zombie', 30, 1, 'bite', 0, 5],
['skeleton', 10, 2, 'sword', 1, 10],
['orc', 15, 4, 'club', 1, 7]
];
creatureObject = creatureArray.reduce(function(accumulator, currentValue, index, array) {
array[index].unshift('species');
//what goes here?
return accumulator;
}, {});
console.log(creatureObject);
Here is how you can do accomplish it.
"use strict";
var creatureArray, creatureObject;
creatureArray = [
['zombie', 30, 1, 'bite', 0, 5],
['skeleton', 10, 2, 'sword', 1, 10],
['orc', 15, 4, 'club', 1, 7]
];
creatureObject = creatureArray.reduce((accumulator, currentValue) => {
return [...accumulator, ['species', ...currentValue]];
}, []);
console.log(creatureObject);
The ... syntax above is called the Spread Operator.
When applied it expands the elements of the array into the new array created by the enclosing [ and ], placing each element from the old array as a top level element into the new array. This results in a flat array instead of a nested array. E.g [[1, 2]] -> [[1, 2]], but [...[1, 2]] -> [1, 2].
This is highly useful because it enables both simple concatenation as well as insertion of top level elements either before or after the expanded array.
Consider:
"use strict";
const names = ['Linus', 'Jane', 'David'];
const withJakeAppended = [...names, 'Jake'];
const withJakePrepended = ['Jake', ...names];
[names, withJakeAppended, withJakePrepended].forEach(xs => console.log(xs));
As you can see, when we spread an Array it is not modified, so the pleasant syntax also enables improved ergonomics for immutable, value oriented programming.
Even better, ... works with Sets and Maps as well. In fact, it works any Iterable object, including ones we can create ourselves.
I might add that using the fourth argument to either Array.prototype.forEach or Array.prototype.forEach is a poor practice that should be avoided.
Note if you need to do this in a browser without ES2015 support, you can write
"use strict";
var creatureArray, creatureObject;
creatureArray = [
['zombie', 30, 1, 'bite', 0, 5],
['skeleton', 10, 2, 'sword', 1, 10],
['orc', 15, 4, 'club', 1, 7]
];
creatureObject = creatureArray.reduce(function (accumulator, currentValue) {
return accumulator.concat([['species'].concat(currentValue)]);
}, []);
console.log(creatureObject);
map is more apropriate in this case:
var creatureArray = [ ['zombie' , 30, 1, 'bite' , 0, 5],
['skeleton', 10, 2, 'sword', 1, 10],
['orc' , 15, 4, 'club' , 1, 7] ]
var creatureObject = creatureArray.map(currentValue => ['species', ...currentValue] )
console.log( JSON.stringify( creatureObject ).replace(/],/g, '],\n ') )
An example in any language would help, though in the end I am going to be using either Ruby or JavaScript/CoffeeScript.
I have an array of pixel values. For example, I have an array that represents the pixels of a 5x5 image.
image = [1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5]
The image would be like:
1 2 3 4 5
6 7 8 9 0
1 2 3 4 5
6 7 8 9 0
1 2 3 4 5
I already have a way of getting rows. But I want a way to also retrieve a column for an index.
Let's say I had a method in Ruby:
class Array
def column(index)
...
end
end
I would like the following results:
image.column(0) #=> [1,6,1,6,1]
image.column(3) #=> [4,9,4,9,4]
EDIT: Thanks to everyone who provided their assistance. Here is what I went with:
def column index
output = []
i = 0
while i < #height
output << pixel(index + (i * #width))
i += 1
end
output
end
Pixel is another method I have that returns an averaged value from an array of RGBA values, given an index.
The reason this suffices is that I can safely assume that every row/column in the image is the correct size. I also wanted to keep the process fairly simplistic as I am likely to make this a CoffeeScript application that will use typed clamped arrays(for performance reasons and the fact that canvas data is a Uint8ClampedArray), in which case the value of output would be a Uint8ClampedArray and I'd be using the index instead of push, since Uint8ClampedArray doesn't/can't support push/pop/shift/unshift.
Many of the other answers will work for an image that is exactly 5x5 as your question specifies but in the case where this is not implicitly true I would build a class for this such as:
class ImageMap
attr_reader :image
def initialize(image,columns=nil)
#image = image.each_slice(columns ||= Math.sqrt(image.size)).to_a
end
def columns
#image.first.size
end
def rows
#image.size
end
def column(n)
#image.map{|a| a[n]}
end
def row(n)
[#image[n]].concat([nil] * columns).take(columns).flatten
end
def cell(column,row)
column(column)[row]
end
def print
#image.each {|a| puts a.join}
end
end
This will handle all images and allows you to also set the number of expected columns as well. If no column expectation is made then it tries to make it square.
Square
image = [1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5]
im = ImageMap.new(image)
im.column(0)
#=> [1, 6, 1, 6, 1]
im.column(3)
#=> [4, 9, 4, 9, 4]
im.row(0)
#=> [1, 2, 3, 4, 5]
im.cell(4,2)
#=> 5
Non Square
image = [1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5]
im = ImageMap.new(image,4)
im.column(0)
#=> [1, 5, 9, 3, 7, 1, 5]
im.columns
#=> 4
im.rows
#=> 7
Obviously this could use some handling for out of bounds values but you should be able to deal with that. Example with non-existent rows/columns:
im.column(7)
#=> [nil, nil, nil, nil, nil]
im.row(7)
#=> [nil, nil, nil, nil, nil]
im.cell(7,2)
#=> nil
Also note if it is not square it will still function e.g.
image = [1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,4] # added a 4
im = ImageMap.new(image)
im.column(0)
#=> [1, 6, 1, 6, 1, 4]
im.column(1)
#=> [2, 7, 2, 7, 2, nil]
im.image
#=> [[1, 2, 3, 4, 5], [6, 7, 8, 9, 0], [1, 2, 3, 4, 5], [6, 7, 8, 9, 0], [1, 2, 3, 4, 5], [4]]
Update based on OP current solution
This method should preform the same function and is a bit more rubyesque
def column index
(0...#height).map { |i| pixel(index + (i * #width)) }
end
image = [1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5]
def column(image, n, row_length)
(n..image.length).step(row_length).map{|i| image[i]}
end
column(image, 3, 5) # => [4, 9, 4, 9, 4]
Rather than creating new methods in the class Array, you might consider creating a separate class. I have assumed the size of image is a multiple of a number of rows--considering the example and that we are talking pixels--but the code obviously could be changed if that assumption were dropped.
Thanks to #SergioTulentsev and #engineersmnky for their suggestions (see comments), which I've implemented.
Code
class Array2D
def initialize(arr, ncols)
raise ArgumentError, "ncols must be positive" if ncols < 1
raise ArgumentError,
"arr.size must a multiple of ncols" unless (arr.size % ncols).zero?
#arr = arr
#ncols = ncols
#nrows = arr.size/ncols
end
def [](r,c) #arr[r*#ncols+c] end
def row(r) #arr[r*#ncols, #ncols] end
def rows_at(*indices) indices.map { |i| row(i) } end
def col(c) #nrows.times.map { |r,a| self[r,c] } end
def cols_at(*indices) indices.map { |i,a| col(i) } end
def array() rows_at(*0...#nrows) end
def transpose() cols_at(*0..#ncols) end
alias :to_s :array
end
Array2D.instance_methods(false)
#=> [:[], :row, :rows_at, :col, :cols_at, :array, :transpose, :to_s]
Note that self is required in self[r,c] in the method col. Without self, [1,2] returns an array.
Example
image = [1,2,3,4,5,6,7,8,9,0,11,12,13,14,15,16,17,18,19,10,21,22,23,24,25]
image2D = Array2D.new(image, 5)
image2D.array
#=> [[ 1, 2, 3, 4, 5],
# [ 6, 7, 8, 9, 0],
# [11, 12, 13, 14, 15],
# [16, 17, 18, 19, 10],
# [21, 22, 23, 24, 25]]
image2D[1,3]
#=> 9
image2D.row(1)
#=> [6, 7, 8, 9, 0]
image2D.rows_at(1,3)
#=> [[6, 7, 8, 9, 0], [16, 17, 18, 19, 10]]
image2D.col(1)
#=> [2, 7, 12, 17, 22]
image2D.cols_at(1,3)
#=> [[2, 7, 12, 17, 22],
# [4, 9, 14, 19, 24]]
image2D.transpose
#=> [[1, 6, 11, 16, 21],
# [2, 7, 12, 17, 22],
# [3, 8, 13, 18, 23],
# [4, 9, 14, 19, 24],
# [5, 0, 15, 10, 25]]
def column(index)
(0...5).map{|i|image[i*5+index]}
end