How to convert Buffer array to hex? - javascript

I am getting a Buffer array back in a JSON object when I call one of my API endpoints. I would like to convert this array to a more "usable" form (hex?) so I can compare them, etc. Here is what the object currently looks like:
"hash": {
"type": "Buffer",
"data": [
151,
14,
51,
26,
46,
52,
5,
151,
99,
107,
38,
188,
138,
180,
76,
56,
108,
214,
135,
213,
125,
134,
105,
139,
129,
236,
206,
157,
67,
1,
12,
12
]
}
How would I go about converting this array to a hex (or string, etc.) so that I can compare hashes?

You can just create a new buffer and convert it into the format you need.
var o = {"hash": {
"type": "Buffer",
"data": [
151,
14,
51,
26,
46,
52,
5,
151,
99,
107,
38,
188,
138,
180,
76,
56,
108,
214,
135,
213,
125,
134,
105,
139,
129,
236,
206,
157,
67,
1,
12,
12
]
}
}
console.log(new Buffer(o.hash,'hex').toString('hex'));
// 970e331a2e340597636b26bc8ab44c386cd687d57d86698b81ecce9d43010c0c

If you have an existing Buffer object, you can represent it as hex via:
myBuffer.toString('hex')
// '970e331a2e340597636b26bc8ab44c386cd687d57d86698b81ecce9d43010c0c'

Use Number.prototype.toString:
var json = '{"hash": {"type": "Buffer","data": [151,14,51]}}';
var parsed = JSON.parse(json);
document.write("data: " + JSON.stringify(parsed.hash.data) + "<br>");
document.write("hex: ");
parsed.hash.data.forEach(function(b) { document.write(("00" + b.toString(16)).substr(-2)); });

Related

How to verify an ES256 (ECDSA using P-256 and SHA-256) signature with window.crypto.subtle?

I'm having trouble figuring out the right parameters to verify a SHA-256 signature that was created with an ECDSA P-256 public key in web crypto. Below script outputs:
Node verify result: true
Web verify result: false
What are the parameters to make verification work with web crypto too? I think I've tried everything by now except the right thing :|
(BTW tried the web piece in Chrome as well with same result)
const crypto = require("crypto");
const webcrypto = require("node:crypto").webcrypto;
const derEncodedPublicKey = Buffer.from(
"MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE5/J6xKyJxzOJ85om+jUJUFHMqnpruqXnKx5jKRojB3E1gC29g/kAc6xHunY05IW+gn2oeAdjggnH7a4WQ8/Afg==",
"base64"
);
const data = new Uint8Array([
73, 150, 13, 229, 136, 14, 140, 104, 116, 52, 23, 15, 100, 118, 96, 91, 143,
228, 174, 185, 162, 134, 50, 199, 153, 92, 243, 186, 131, 29, 151, 99, 5, 0,
0, 0, 0, 182, 173, 217, 158, 122, 216, 45, 140, 214, 44, 204, 209, 62, 118,
45, 12, 238, 10, 91, 88, 80, 235, 131, 5, 70, 171, 245, 252, 71, 13, 207, 235,
]);
const sig = new Uint8Array([
48, 68, 2, 32, 58, 26, 13, 251, 116, 195, 219, 77, 90, 1, 64, 38, 54, 249, 56,
87, 235, 24, 78, 26, 13, 88, 74, 224, 159, 58, 159, 133, 111, 98, 69, 214, 2,
32, 87, 1, 32, 191, 170, 10, 33, 204, 86, 124, 73, 21, 153, 4, 58, 182, 248,
175, 144, 80, 146, 173, 247, 205, 36, 51, 59, 221, 212, 133, 107, 118,
]);
function nodeVerify() {
const nodeKey = crypto.createPublicKey({
format: "der",
key: derEncodedPublicKey,
type: "spki",
});
const v = crypto.createVerify("SHA256").update(data);
return v.verify(nodeKey, sig);
}
async function webVerify() {
const webkey = await webcrypto.subtle.importKey(
"spki",
derEncodedPublicKey,
{
name: "ECDSA",
namedCurve: "P-256",
},
false,
["verify"]
);
return webcrypto.subtle.verify(
{
name: "ECDSA",
hash: "SHA-256",
},
webkey,
sig,
data
);
}
(async () => {
console.log("Node verify result:", nodeVerify());
console.log("Web verify result:", await webVerify());
})().catch(console.error);
NodeJS is easier, it needs less parameters :)
Thank you.
After more googling and trying I found the answer: the ECDSA signature that I am using, is actually an ASN.1 encoded structure. NodeJS is fine with that during verification, however webcrypto not--it wants the raw signature, which is the byte concatenation of the 2 integers in the ASN.1 encoded signature.
More information in this post: https://crypto.stackexchange.com/questions/57731/ecdsa-signature-rs-to-asn1-der-encoding-question

ICryptoTransform decryptor C# equivalent in reactjs

I am migrating from .net core to reactjs and need to Decrypt Hash to object. I stuck here where results are not equal. Here is the code of .net.
Note: cipherText length is 656 I can't paste such a long array here.
byte[] cipherText = [132, 185, 138, 129, 38, 216, 49, 48, 25, 139, 187, 146, 67, 234, 194, 143, 252, 214, 245, 230, 30, 238, 235, 53, 155, 136, 0, 112, 76, 27, 205, 84, 124, 250, 74, 114, 208, 227, 148, 135, 112, 168, 171, 73, 45, 122, 31, 248, 186, 80, 148, 143, 251, 216, 90, 152, 138, 130, 148, 199, 178, 151, 151, 195, 252, 43, 67, 183, 45, 24, 228, 73, 208, 249, 155, 36, 78, 232, 210, 20, 235, 109, 206, 245, 180, 28, 227, 32, 202, 143, 255, 110, 128, 38, 101, 174, 253, 80, 171, 201......]
plaintext = null;
byte[] Key = [56, 63, 82, 186, 73, 8, 112, 110, 129, 185, 157, 192, 163, 160, 120, 215, 52, 254, 252, 189, 25, 82, 43, 15, 87, 98, 48, 193, 21, 44, 6, 163]0: 561: 632: 823: 1864: 735: 86: 1127: 1108: 1299: 18510: 15711: 19212: 16313: 16014: 12015: 21516: 5217: 25418: 25219: 18920: 2521: 8222: 4323: 1524: 8725: 9826: 4827: 19328: 2129: 4430: 631: 163];
byte[] IV = [200, 97, 110, 6, 23, 248, 144, 210, 223, 167, 67, 64, 125, 96, 136, 201]
using (AesManaged aesAlg = new AesManaged())
{
aesAlg.Key = Key;
aesAlg.IV = IV;
ICryptoTransform decryptor = aesAlg.CreateDecryptor(aesAlg.Key, aesAlg.IV);
using (MemoryStream msDecrypt = new MemoryStream(cipherText))
{
using (CryptoStream csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read))
{
using (StreamReader srDecrypt = new StreamReader(csDecrypt))
{
plaintext = srDecrypt.ReadToEnd();
}
}
}
}
How can I decrypt byte array with cryptojs?
I solved it, Here is the solution:
var strHexWA = (CryptoJS.lib.WordArray.create(new Uint8Array(cipherText)));
var KeyWA = (CryptoJS.lib.WordArray.create(new Uint8Array(Key)));
var IVWA = (CryptoJS.lib.WordArray.create(new Uint8Array(IV)));
var decrypt = CryptoJS.AES.decrypt({
ciphertext: strHexWA
}, KeyWA, {
iv: IVWA,
padding: CryptoJS.pad.Pkcs7,
mode: CryptoJS.mode.CBC
});
var plaintext = decrypt.toString(CryptoJS.enc.Utf8);
return plaintext;

Cannot save to Firestore array of integers and floats

I am using Firestore to save an array of integers and floats.
However, Firestore wont allow me to save that array and does not return an error (in the catch statement for example)
My array is the size of 71201
(71201) [84, 96, 96, 96, 91.8, 97, 98, 98, 98, 99, 99, 99, 99, 99, 98, 98, 98, 98, 98, 98, 98, 96, 95, 93, 91, 89, 88, 87, 87, 87, 88, 89, 91, 94, 96, 98, 99, 100, 101, 101, 101, 98, 96, 92, 89, 87, 87, 87, 87, 89, 91, 93, 95, 96, 97, 98, 98, 99, 99, 100, 100, 100, 100, 100, 100, 101, 102, 103, 104, 105, 106, 108, 109, 110, 111, 113, 113, 114, 115, 116, 117, 117, 118, 118, 119, 120, 120, 121, 122, 122, 122, 123, 124, 124, 125, 126, 127, 127, 127, 127, …]
Reading the limit documentation the size of an integer is 8 Bytes
So trying to do some math here (and possibly failing)
71201*8/1024 =
556.2578125
So that is ~556KB
That as I understand is not a problem with the limit.
Also I can only imagine that this is the problem (not accepting this large array) due to the network tab view:
Opening one of the requests looks like this on the headers:
and the response is always empty
The catch statement of the promise does not get called and I have waited for many minutes (neither the then)
this.afs.collection('events').doc(event.getID()).set({values: test}).then((some) => {
debugger;
}).catch((e) => {
debugger;
});
Any ideas what can I be doing wrong?
P.S. It's been now about 20minutes and my network tab keeps growing with those failed requests.
UPDATE
If I Make this array a string via eg JSON.stringify then the operation saves within seconds.

Convert a variable containing UTF8 string to a variable containing latin1 string - for browser in Javascript

Bash alternative (shell set to UTF8):
Input:
in.json
$ file -I in.json
in.json: text/plain; charset=utf-8
{"it-it":"Città"}
Bash command I need the JS alternative for:
$ iconv -f utf8 -t latin1 in.json > out.json
out.json
$ file -I in.json
out.json: text/plain; charset=iso-8859-1
{"it-it":"Citt?"}
What Javascript sees in browser for in.json when read as base64 from an input type="file" (despite content-type and script encoding set to utf8):
{"it-it":"Città"}
What Javascript sees in browser for out.json:
{"it-it":"Città"}
Question - how can I make in the most native Javascript way to make most modern browsers convert this utf8 string
({"it-it":"Città "} as latin1 and {"it-it":"Città"} as utf8)
to a latin1 string?
I prefer a native solution, or worst case JQuery, please try not to solve it with an npm + node dependency hell.
P.s.: I only need to support the most modern browsers, this is for an admin-only page.
Below I've created an array with iso-8859-1version of CittÃ, and then used TextDecoder to decode it,.
So if you can get the binary version of the JSON, this should be able to convert for you.
//CittÃ
var latinSource = new Uint8Array([67, 105, 116, 116, 195]);
var tc = new TextDecoder("iso-8859-1");
console.log(tc.decode(latinSource));
For me, 'new TextDecoder("iso-8859-1")' not working...
1.
var latinSource = new Uint8Array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255]);
var tc = new TextDecoder("iso-8859-1");
console.log(tc.decode(latinSource)); //return windows-1252 string
I see, the result, it's not a latin1 string, because this contains character '€'.
2.
//windows-1252
console.log('new TextDecoder("iso-8859-1")', new TextDecoder("iso-8859-1"));
// ---->
//new TextDecoder("iso-8859-1") {
// "encoding": "windows-1252",
// "fatal": false,
// "ignoreBOM": false,
// "decode": function decode() { [native code] }
//}
Working way to encode-decode latin-1:
//Decode Latin1-string (iso-8859-1 encoded string) -> into Uint8Array
function Latin1ToUint8Array(iso_8859_1){
var uInt8Arr = new Uint8Array(iso_8859_1.length);
for(var i=0; i<iso_8859_1.length; i++){
uInt8Arr[i] = iso_8859_1.charCodeAt(i);
}
return uInt8Arr;
}
//encode Uint8Array -> into iso-8859-1 encoded string (latin1-string)
function Uint8ToLatin1Str(Uint8Arr){
var iso_8859_1_string = '';
for(var i=0; i<Uint8Arr.length; i++){iso_8859_1_string+= String.fromCharCode(Uint8Arr[i]);}
return iso_8859_1_string;
}
var latinSource = new Uint8Array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255]);
console.log( Uint8ToLatin1Str(latinSource) ); //valid latin1-string (iso-8859-1)
Finally, Windows-1252 conversions:
function Windows1252EncodeDecode(
cp1252 //string (to encode into bytes), or Uint8Array (to decode into string)
){
var replaceCharCodesForLatin1 = {
//_______________________________________________________________________
//|"windows-1252"| iso-8859-1 | //Unicode |
//|'character' | charcode, | //charcode(commented), |
//|______________|______________________|_______________________________|
'€' : 128, //8364,
'‚' : 130, //8218,
'ƒ' : 131, //402,
'„' : 132, //8222,
'…' : 133, //8230,
'†' : 134, //8224,
'‡' : 135, //8225,
'ˆ' : 136, //710,
'‰' : 137, //8240,
'Š' : 138, //352,
'‹' : 139, //8249,
'Œ' : 140, //338,
'Ž' : 142, //381,
'‘' : 145, //8216,
'’' : 146, //8217,
'“' : 147, //8220,
'”' : 148, //8221,
'•' : 149, //8226,
'–' : 150, //8211,
'—' : 151, //8212,
'˜' : 152, //732,
'™' : 153, //8482,
'š' : 154, //353,
'›' : 155, //8250,
'œ' : 156, //339,
'ž' : 158, //382,
'Ÿ' : 159, //376
};
if(typeof cp1252 === 'string'){ //if that was been string to encode to bytes
var resultUint8 = new Uint8Array(cp1252.length);
for(var i = 0; i<cp1252.length; i++){
var charCode = cp1252[i].charCodeAt(0);
resultUint8[i] = ((charCode>256) ? replaceCharCodesForLatin1[cp1252[i]] : charCode);
}
return resultUint8; //return Uint8Array
}else if(cp1252 instanceof Uint8Array){ //else if that was been Uint8Array to decode to string
var resultString = "";
for(var i = 0; i<cp1252.length; i++){
var charCode = (Object.keys(replaceCharCodesForLatin1).find(key => replaceCharCodesForLatin1[key] === cp1252[i]));
charCode = (typeof charCode === 'undefined') ? String.fromCharCode(cp1252[i]) : charCode;
resultString += charCode;
}
return resultString; //return Uint8Array
}
}
var latinSource = new Uint8Array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255]);
var windows1252 = new TextDecoder("iso-8859-1").decode(latinSource); //windows-1252 string on output
console.log('new TextDecoder("iso-8859-1").decode(latinSource)', (new TextDecoder("iso-8859-1").decode(latinSource)))
var bytesBack = Windows1252EncodeDecode(windows1252);
console.log('bytesBack', bytesBack.toString());
var Windows1252StringBack = Windows1252EncodeDecode(bytesBack)
console.log('string back', Windows1252StringBack);
console.log('Compare with TextDecoder', (Windows1252StringBack === windows1252 ));
Modification of latin-1 functions, from 3:
function isLatin1String(str){return (str.match(/[^\u0000-\u00FF]/) === null);} //check is string "iso-8859-1"-encoded or not (true/false)
//Decode Latin1 or utf-8 string -> into Uint8Array
function StringToUint8Array(str){
if(!isLatin1String(str)){
return new TextEncoder("utf-8").encode(str); //encode to bytes as utf-8
}
//else, as ASCII-compatible latin1-string
var uInt8Arr = new Uint8Array(str.length);
for(var i=0; i<str.length; i++){
uInt8Arr[i] = str.charCodeAt(i);
}
return uInt8Arr;
}
//encode Uint8Array -> to latin1-string
function Uint8ToStr(Uint8Arr){
var iso_8859_1_string = '';
for(var i=0; i<Uint8Arr.length; i++){iso_8859_1_string+= String.fromCharCode(Uint8Arr[i]);}
return iso_8859_1_string;
}
function latin1ToUtf8(latin1str){
return new TextDecoder("utf-8").decode(StringToUint8Array(latin1str));
}
console.log('StringToUint8Array("CittÃ")', StringToUint8Array("CittÃ")); //Latin1
console.log('StringToUint8Array("Città€")', StringToUint8Array("Città€")); //utf-8
console.log('Uint8ToStr(StringToUint8Array("CittÃ"))', Uint8ToStr(StringToUint8Array("CittÃ"))); //latin1
console.log('Uint8ToStr(StringToUint8Array("Città"))', Uint8ToStr(StringToUint8Array("Città€"))); //utf-8
console.log('latin1ToUtf8(Uint8ToStr(StringToUint8Array("Città€")))', latin1ToUtf8(Uint8ToStr(StringToUint8Array("Città€")))); //utf-8

Efficient way of finding the 5 largest numbers in an array at any given interval

I am trying to find the five largest numbers at set intervals, while also Removing those values from the array. I need to grab the top candidates in their respective range. That range can change and the number that I need to query can also change. Is there an efficient and preferably elegant solution to this? By elegance, I mean an algorithmic (preferably hashed) approach that removes inefficient sorting or actions that do not contribute to performance on sparse and large arrays.
var arr = [101, 88, 267, 175, 154, 39, 74, 217, 31, 105, 235, 31, 14, 49, 226, 195, 134, 207, 222, 281,
262, 112, 133, 115, 0, 53, 128, 103, 88, 145, 238, 13, 204, 199, 100, 247, 292, 157, 141, 286,
72, 160, 85, 61, 57, 54, 263, 50, 125, 179, 243, 281, 39, 76, 151, 79, 1, 238, 200, 249, 35, 82,
204, 174, 293, 216, 84, 209, 170, 236, 3, 247, 25, 162, 25, 57, 49, 215, 8, 167, 180, 268,
204, 257, 134, 151, 191, 81, 77, 106, 85, 128, 52, 136, 46, 185, 229, 116, 145, 253, 258, 222,
269, 225, 101, 175, 265, 77, 32, 8, 72, 54, 111, 264, 292, 161, 91, 215, 139, 245, 73, 127, 297,
73, 258, 183, 232, 55, 199, 175, 31, 24, 21, 155, 231, 95, 40, 223, 222, 86, 115, 210, 134, 229,
211, 54, 294, 153, 52, 165, 168, 125,186, 185, 289, 188, 248, 61, 136, 15, 19, 92, 200, 80, 208,
195, 241, 85, 288, 279, 119, 247, 208, 11, 80, 111, 29, 292, 222, 289, 70, 11, 209, 25, 267, 233,
16, 289, 154, 141, 174, 30, 156, 40, 266, 139, 116, 241, 1, 101, 109, 61, 220, 265, 45, 178, 166,
102, 181, 193, 202, 133, 200, 266, 114, 222, 231, 89, 190, 29, 20, 64, 233, 261,213, 40, 161, 167,
100, 121, 288, 268, 50, 264, 78, 105, 21, 33, 79, 114, 5, 134, 56, 259, 124, 44, 134, 133, 74, 176,
65, 68, 34, 56, 2, 287, 63, 167, 299, 59, 290, 241, 104, 75, 76, 116, 225, 297, 208, 136, 265, 290,
170, 267, 10, 176, 141, 217, 195, 4, 173, 32, 150, 271, 238, 171, 195, 16, 282, 77, 62, 39, 44, 248,
270, 222, 295, 122, 190, 230];
function maxAtIntervals (intervalLength, select, xs) {
const comparator = (a, b, _) => a - b;
const temp = [];
for (var i = 0; i < xs.length; i += intervalLength) {
const interval = xs.slice(i, i + intervalLength);
temp.push(interval.sort(comparator).slice(-select));
}
return temp;
}
console.log(maxAtIntervals(20, 5, arr));
.as-console-wrapper { max-height: 100% !important; top: 0; }
I have read #le_m's comment however finding the k largest / smallest items or the kth largest / smallest item is a complicated task in O(n). It's best implemented in sorting and taking the necessary ones from the beginning of the array.
Accordingly you may do as follows;
function segmentAndTakeMax(ar,sl,mc) { // array , segment length, max count
var tempar = Array.from({length: sl});
return Array.from({length: Math.ceil(ar.length/sl)})
.map((_,i) => tempar.map((_,j) => arr[i*sl+j])
.sort((a,b) => b-a)
.slice(0,Math.min(arr.length-i*sl,mc)));
}
var arr = Array.from(new Array(203), _ => ~~(Math.random()*100));
console.log(arr);
console.log(segmentAndTakeMax(arr,20,5));
.as-console-wrapper { max-height: 100% !important; top: 0; }
Ok as per OP's performance concerns on V8 i have repharsed the code to use .reduce() which is much faster than .map() in V8. Here is the modified code.
function segmentAndTakeMax(arr, n, m) {
var li = arr.length-1; // last index
return arr.reduce((r,e,i,a) => i%n ? (r[r.length-1].push(e), // if i%n != 0 then do these -> push e to last sub array
i == li && (r[r.length-1] = r[r.length-1].sort((a,b) => b-a).slice(0,m)), // short circuit for if i == last index then sort and slice the last sub array
r) // return r
: (i && (r[r.length-1] = r[r.length-1].sort((a,b) => b-a).slice(0,m)), // if i%n == 0 then do these -> short circuit for if i != 0 then sort and slice the last sub array
r.push([e]), // push [e] (a new sub array) to r
r), []); // return r
}
var arr = Array.from(new Array(203), _ => ~~(Math.random()*100));
console.log(arr);
console.log(segmentAndTakeMax(arr,20,5));
.as-console-wrapper { max-height: 100% !important; top: 0; }

Categories

Resources