At the minute I find myself stuck trying to flatten a Uint8ClampedArray
.
The starting array structure is data = [227, 138, 255…]
and after creating an array from that of the like enc = [Uint8ClampedArray[900], Uint8ClampedArray[900], Uint8ClampedArray[900]...]
I try to flatten it.
I tried many methods / solutions for that but no one seems to work:
the MDN suggested method
var flattened = [[0, 1], [2, 3], [4, 5]].reduce(function(a, b) {
return a.concat(b);
}, []);
with concat
data = [].concat.apply([], enc);
and through a function
function flatten(arr) {
return arr.reduce(function (flat, toFlatten) {
return flat.concat(Array.isArray(toFlatten) ? flatten(toFlatten) : toFlatten);
}, []);
}
but no joy so far, it keeps returning the array as it is. Anyone can point me in the right direction and explain why is that?
-EDIT- Bottom line: I need it to return a regular Array object, like the starting one not typed.
At the minute I find myself stuck trying to flatten a Uint8ClampedArray
.
The starting array structure is data = [227, 138, 255…]
and after creating an array from that of the like enc = [Uint8ClampedArray[900], Uint8ClampedArray[900], Uint8ClampedArray[900]...]
I try to flatten it.
I tried many methods / solutions for that but no one seems to work:
the MDN suggested method
var flattened = [[0, 1], [2, 3], [4, 5]].reduce(function(a, b) {
return a.concat(b);
}, []);
with concat
data = [].concat.apply([], enc);
and through a function
function flatten(arr) {
return arr.reduce(function (flat, toFlatten) {
return flat.concat(Array.isArray(toFlatten) ? flatten(toFlatten) : toFlatten);
}, []);
}
but no joy so far, it keeps returning the array as it is. Anyone can point me in the right direction and explain why is that?
-EDIT- Bottom line: I need it to return a regular Array object, like the starting one not typed.
Share Improve this question edited Jun 2, 2022 at 8:52 Yves M. 31k24 gold badges109 silver badges149 bronze badges asked Jun 29, 2016 at 2:10 iomviomv 2,70721 silver badges30 bronze badges 04 Answers
Reset to default 7If enc
is an Array
of Uint8ClampedArray
s, this one-liner statement should work:
var flattened = Uint8ClampedArray.from(enc.reduce((a, b) => [...a, ...b], []));
This is equivalent to:
var flattened = Uint8ClampedArray.from(enc.reduce(function(a, b){
return Array.from(a).concat(Array.from(b));
}, []));
To answer your actual question as to why reduce
didn’t work for you:
[].concat(Uint8ClampedArray([1, 2, 3, 4]));
unfortunately doesn’t return [1, 2, 3, 4]
but [Uint8ClampedArray[4]]
. concat
doesn’t work with Typed Arrays.
I would calculate the total length first and then use set
. The advantage of set
is
If the source array is a typed array, the two arrays may share the same underlying ArrayBuffer; the browser will intelligently copy the source range of the buffer to the destination range.
function flatten(arrays, TypedArray) {
var arr = new TypedArray(arrays.reduce((n, a) => n + a.length, 0));
var i = 0;
arrays.forEach(a => { arr.set(a,i); i += a.length; });
return arr;
}
console.log(flatten(
[new Uint8ClampedArray([1,2,3]), new Uint8ClampedArray([4,5,6])],
Uint8ClampedArray
));
An alternative is using blobs, as proposed by guest271314. The proper way would be
function flatten(arrays, TypedArray, callback) {
var reader = new FileReader();
reader.onload = () => {
callback(new TypedArray(reader.result));
};
reader.readAsArrayBuffer(new Blob(arrays));
}
flatten(
[new Uint8ClampedArray([1,2,3]), new Uint8ClampedArray([4,5,6])],
Uint8ClampedArray,
result => console.log(result)
);
Checking the MDN, TypedArray
s doesn't share quite a few normal JS array functions.
You can collect the values from the clamped array, and initialize a new one like this however:
var enc = [Uint8ClampedArray.of(1, 2), Uint8ClampedArray.of(4, 8), Uint8ClampedArray.of(16, 32)]
var flattened = Uint8ClampedArray.from(enc.reduce(function(acc, uintc){
Array.prototype.push.apply(acc, uintc)
return acc;
}, []));
console.log(flattened); // [object Uint8ClampedArray]
console.log(flattened.join(',')); // "1,2,4,8,16,32"
Edit, Updated
firefox, nightly presently returns [[object Uint8ClampedArray],[object Uint8ClampedArray],[object Uint8ClampedArray]]
at FileReader()
result
as pointed out by @Oriol.
An approach using spread element
, rest element
, for..of
, which returns same results as chromium, chrome utilizing Blob()
, FileReader()
; TextEncoder()
, TextDecoder()
; JSON.parse()
approaches
var enc = [new Uint8ClampedArray(900)
, new Uint8ClampedArray(900)
, new Uint8ClampedArray(900)];
var res = [];
for (let prop of enc) [...res] = [...res, ...prop];
console.log(res);
or, briefer, as suggested by @Oriol
var res = [];
var enc = [new Uint8ClampedArray(900), new Uint8ClampedArray(900)];
for (let prop of enc) res.push(...prop);
You can use Blob()
which concatenates parameters into single Blob
object, FileReader()
, JSON.parse()
var enc = [new Uint8ClampedArray(900)
, new Uint8ClampedArray(900)
, new Uint8ClampedArray(900)];
var blob = new Blob([enc]);
var reader = new FileReader();
reader.onload = () => {
console.log(JSON.parse("[" + reader.result + "]"))
}
reader.readAsText(blob);
alternatively, using TextEncoder()
, TextDecoder()
, JSON.parse()
var enc = [new Uint8ClampedArray(900)
, new Uint8ClampedArray(900)
, new Uint8ClampedArray(900)];
var encoder = new TextEncoder();
var arr = encoder.encode(enc);
var decoder = new TextDecoder();
var res = JSON.parse("[" + decoder.decode(arr) + "]");
console.log(res);