I have two arrays both are of variable length, I want to achieve a pattern, which I have already achieved but not satisfied with my solution. I believe there could be a better way to achieve the same.
const logic = (outerArray, innerArray) => outerArray.map((outerVal, OuterIndex) => {
return innerArray.map((innerVal, innerIndex) => {
const currentSlideIndex = OuterIndex + 1;
if (innerArray.length < 6 && innerIndex + 1 === currentSlideIndex) return true;
if (innerArray.length === 6) {
if (innerIndex < 4 && innerIndex + 1 === currentSlideIndex) return true;
// return false if currentslide is greater than four and less than last two slides
if (currentSlideIndex > 4 && currentSlideIndex < outerArray - 1 && innerIndex === 3) {
return true;
}
if (innerIndex === 4 && currentSlideIndex === outerArray - 1) return true;
if (innerIndex === 5 && currentSlideIndex === outerArray) return true;
}
return '';
});
});
Expected results
if innerArray length is less than or equal to 6 it should return array of length as innerArray and also the output should look like
logic([1,2,3,4,5],[1,2,3,4,5])
Expected output
[
[true, "", "", "", ""],
["", true, "", "", ""],
["", "", true, "", ""],
["", "", "", true, ""],
["", "", "", "", true]
]
if outerArray length is greater than 6 then it should work same for 3 index and should return true for index 4 for all outerArray index and resume at last two index.
logic([1,2,3,4,5,6,7,8,9,10],[1,2,3,4,5,6])
Expected output
[
[true,"","","","",""],
["",true,"","","",""],
["","",true,"","",""],
["","","",true,"",""],
["","","",true,"",""],
["","","",true,"",""],
["","","",true,"",""],
["","","",true,"",""],
["","","","",true,""],
["","","","","",true]
]
I would split your code into two functions. The first one would return the column index of each value of your outerArray like so:
const getColumnIndexes = (array) => {
// Get first 3 items
let columnIndexes = array.slice(0, 3);
// Get items in 4th column
columnIndexes = columnIndexes.concat(array.slice(3, Math.max(4, array.length - 2)).map(() => 4));
// Get last 2 items
columnIndexes = columnIndexes.concat(array.slice(Math.max(4, array.length - 2), array.length).map((val, index) => 5 + index));
return columnIndexes;
};
Then your logic function becomes really simple:
const logic = outerArray => {
const columnIndexes = getColumnIndexes(outerArray);
return outerArray.map((val, lineIndex) => {
return Array(Math.min(6, outerArray.length)).fill().map((_, i) => i === columnIndexes[lineIndex] - 1 ? true : "");
});
};
If I understood properly, you don't actually need this innerArray anymore.
logic([1, 2, 3, 4, 5]);
[
[true, "", "", "", ""],
["", true, "", "", ""],
["", "", true, "", ""],
["", "", "", true, ""],
["", "", "", "", true]
]
logic([1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
[
[true,"","","","",""],
["",true,"","","",""],
["","",true,"","",""],
["","","",true,"",""],
["","","",true,"",""],
["","","",true,"",""],
["","","",true,"",""],
["","","",true,"",""],
["","","","",true,""],
["","","","","",true]
]
Related
I am currently in the process of making a Connect Four AI using the minimax algorithm. I have made the board and win/draw checks, and have finished implementing the AI. However, when I go to test it, I get the following error:
Uncaught TypeError: Cannot create property '35' on string ''
at Board.insert (board.js:394:26)
at player.js:29:15
at Array.forEach (<anonymous>)
at Player.getBestMove (player.js:27:33)
at script.js:8:20
I have looked through every similar question I could find, and Google has not been of any more help. I am basing most of these functions off of this Tic-Tac-Toe AI tutorial, but the getLowestEmptyCell() method is my own.
board.js:
export default class Board {
constructor(state = ["", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", ""]) {
this.state = state;
}
printFormattedBoard() {
let formattedString = '';
this.state.forEach((cell, index) => {
formattedString += cell ? ` ${cell} |` : ` |`;
if ((index + 1) % 7 === 0) {
formattedString = formattedString.slice(0, -1);
if (index < 41) formattedString += '\n\u2015\u2015\u2015 \u2015\u2015\u2015 \u2015\u2015\u2015 \u2015\u2015\u2015 \u2015\u2015\u2015 \u2015\u2015\u2015 \u2015\u2015\u2015\n'
}
});
console.log('%c' + formattedString, 'color: #c11dd4; font-size: 16px;');
}
isEmpty() {
return this.state.every(cell => !cell);
}
isFull() {
return this.state.every(cell => cell);
}
isTerminal() {
if (this.isEmpty()) return false;
/* 320 lines of winning combinations */
if (this.isFull()) {
return { 'winner': 'draw' };
}
return false;
}
getLowestEmptyCell(index) {
if (index > 41 || index < 0 || this.state[index]) return NaN;
let i = 0;
if (index >= 0) i = 35;
if (index >= 7) i = 28;
if (index >= 14) i = 21;
if (index >= 21) i = 14;
if (index >= 28) i = 7;
if (index >= 35) i = 0;
for (i; i > -1; i -= 7) {
if (!this.state[index + i]) return index + i;
}
}
insert(symbol, position) {
if (![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].includes(position)) throw new Error('Cell index does not exist or is not possible!');
if(!['r', 'y'].includes(symbol)) throw new Error('The symbol can only be an r or a y!');
if (this.state[position]) return false;
position = this.getLowestEmptyCell(position);
this.state[position] = symbol; // error thrown here
return true;
}
getAvailableMoves() {
let moves = [];
for (let i = 0; i < 7; i++) {
if (!this.state[i]) moves.push(this.getLowestEmptyCell(i));
}
return moves;
}
}
player.js:
import Board from './board.js';
export default class Player {
constructor(maxDepth = -1) {
this.maxDepth = maxDepth;
this.nodesMap = new Map();
}
getBestMove(board, maximising = true, callback = () => {}, depth = 0) {
if (depth === 0) this.nodesMap.clear();
if (board.isTerminal() || depth === this.maxDepth) {
if (board.isTerminal().winner === 'r') {
return 100 - depth;
} else if (board.isTerminal().winner === 'y') {
return -100 + depth;
}
return 0;
}
if (maximising) {
let best = -100;
board.getAvailableMoves().forEach(index => {
const child = new Board([...board.state]);
child.insert('r', index);
const nodeValue = this.getBestMove(child, false, callback, depth + 1);
best = Math.max(best, nodeValue);
if (depth === 0) {
const moves = this.nodesMap.has(nodeValue) ? `${this.nodesMap.get(nodeValue)},${index}` : index;
this.nodesMap.set(nodeValue, moves);
}
});
if (depth === 0) {
let returnValue;
if (typeof this.nodesMap.get(best) === 'string') {
const arr = this.nodesMap.get(best).split(',');
returnValue = arr[Math.floor(Math.random() * arr.length)];
} else {
returnValue = this.nodesMap.get(best);
}
callback(returnValue);
return returnValue;
}
return best;
}
if (!maximising) {
let best = 100;
board.getAvailableMoves().forEach(index => {
const child = new Board([...board.state]);
child.insert('y', index);
const nodeValue = this.getBestMove(child, false, callback, depth + 1);
best = Math.max(best, nodeValue);
if (depth === 0) {
const moves = this.nodesMap.has(nodeValue) ? `${this.nodesMap.get(nodeValue)},${index}` : index;
this.nodesMap.set(nodeValue, moves);
}
});
if (depth === 0) {
let returnValue;
if (typeof this.nodesMap.get(best) === 'string') {
const arr = this.nodesMap.get(best).split(',');
returnValue = arr[Math.floor(Math.random() * arr.length)];
} else {
returnValue = this.nodesMap.get(best);
}
callback(returnValue);
return returnValue;
}
return best;
}
}
}
script.js:
import Board from './classes/board.js';
import Player from './classes/player.js';
const board = new Board(["", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", ""]);
const player = new Player();
console.log(player.getBestMove(board));
board.printFormattedBoard();
//console.log(player.nodesMap);
I sense that this is not anything to do with the functionality itself, but rather my cluelessness and trying to implement a custom function in the wrong places.
UPDATE: After doing many console.logs (but probably not enough), I have determined that using an array to initialise a new Board class along with ...board.state actually allows the insert() function to see that there is still, in fact, a usable this.state value with 42 empty strings in an array.
I guess that Board.state is a string (instead of the array that you may expect).
Since strings are immutable, the following assignment is illegal and may (depending on your js-engine) throw the error that you mentioned:
const state: any = "x";
state[35] = 1;
Playgrond Example
click Run to see the expected error
To test, if this is really the case you can set a breakpoint on the line that throws and check the state variable or log the type console.log(this.state, typeof this.state)
To avoid such issues, you should check the type of the state parameter in the constructor and throw an error if it's not of the expected type (i.e. array of string) - or use typescript which will help for such simple errors (note, that the Playgrond Example shows an error on the assignment line and shows a meaningful error when you hoover the mouse over the line: "Index signature in type 'String' only permits reading."
How can I filter for "mna" ===1 and ignore null values
const words = [null, null, {"mna":1}, {"mna":2}, {"mna":1}];
const result = words.filter(word => word.mna === 1);
Just add it to the condition so you don't try to access mna unless it's truthy (null values are falsy so they will cause the condition to short circuit early)
const words = [null, null, {"mna":1}, {"mna":2}, {"mna":1}];
const result = words.filter(word => word && word.mna === 1);
console.log(result);
You can add word && word.mna === 1 to check if word is defined first. The value will be filtered out if it's falsy (null,undefined)
const words = [null, null, {"mna":1}, {"mna":2}, {"mna":1}];
const result = words.filter(word => word && word.mna === 1);
console.log(result);
Alternatively use
Optional chaining:
const words = [null, null, {"mna":1}, {"mna":2}, {"mna":1}];
const result = words.filter(word => word?.mna === 1);
console.log(result);
Works also when the entry exists but the element is missing
const words = [{
"count": "3",
"noMNA": true
}, {
"count": "3",
"mna": 1
}, {
"count": "2",
"mna": 2
}, {
"count": "3",
"mna": 1
}];
const result = words.filter(word => word?.mna === 1);
console.log(result);
I have data that is coming from the server like this
let value = [
{
'commongId': 1,
'principal': true,
'creationDate': '2019-11-03:40:00'
},
{
'commongId': 2,
'principal': false,
'creationDate': '2017-10-25T01:35:00'
},
{
'commongId': 2,
'principal': true,
'creationDate': '2019-05-25T08:00:00'
},
{
'commongId': 1,
'principal': false,
'creationDate': '2018-11-25T09:40:00'
},
{
'commongId': 1,
'principal': false,
'creationDate': '2017-11-25T09:40:00'
},
{
'commongId': 2,
'principal': false,
'creationDate': '2018-05-25T08:00:00'
},
]
I want to transform it in a way that the courses are grouped by commonId, and that the principal course of each 'id' should appear first, and the rest of the courses belonging to the same commonId come after that principal course sorted by the creation date (asc).
So basically the output should be
let value = [
{
commongId: 1,
principal: true,
creationDate: '2019-11-03:40:00'
},
{
commongId: 1,
principal: false,
creationDate: '2017-11-25T09:40:00'
},
{
commongId: 1,
principal: false,
creationDate: '2018-11-25T09:40:00'
},
{
commongId: 2,
principal: true,
creationDate: '2019-05-25T08:00:00'
},
{
commongId: 2,
principal: false,
creationDate: '2017-10-25T01:35:00'
},
{
commongId: 2,
principal: false,
creationDate: '2018-05-25T08:00:00'
}
];
I have a working solution, which in my opinion looks horrible and too complicated.
// function to group the the courses by commonId
const groupBy = (data, keyFn) =>
data.reduce((agg, item) => {
const group = keyFn(item);
agg[group] = [...(agg[group] || []), item];
return agg;
}, {});
let transformedValue = groupBy(courses, item => item.commonId);
//removing the keys from the array of objects
transformedValue = Object.keys(transformedValue).map(k => transformedValue[k]);
// sorting each inner array by creationDate
transformedValue = transformedValue.map(el => {
let modified = el.sort((a, b) =>
moment(a.creationDate).diff(moment(b.creationDate))
);
// pushing the principal object of each array to the top
const foundIndex = modified.findIndex(element => element.principal);
if (foundIndex > -1) {
const foundElement = modified.find(element => element.principal);
modified.splice(foundIndex, 1);
modified.unshift(foundElement);
}
return modified;
});
// flattening the array to one level
transformedValue = transformedValue.flat();
// using the transformed value in the subscription
of(transformedValue).subscribe(p => {
this.dataToShow = p;
});
You could use sort like this.
const value=[{commongId:1,principal:true,creationDate:"2019-11-03:40:00"},{commongId:2,principal:false,creationDate:"2017-10-25T01:35:00"},{commongId:2,principal:true,creationDate:"2019-05-25T08:00:00"},{commongId:1,principal:false,creationDate:"2018-11-25T09:40:00"},{commongId:1,principal:false,creationDate:"2017-11-25T09:40:00"},{commongId:2,principal:false,creationDate:"2018-05-25T08:00:00"},];
value.sort((a, b) => a.commongId - b.commongId
|| b.principal - a.principal
|| a.creationDate.localeCompare(b.creationDate)
)
console.log(value)
The array will first be sorted based on commongId. If both have the same commongId, the subtraction will return 0. So, || will check the next expression because 0 is falsy value.
Then, it will be sorted based on principal. You can subtract 2 boolean values because it returns 1, -1 or 0 based on the value.
true - false === 1
false - true === -1
true - true === 0
If they still have the same value for commongId and principal, the array will be sorted based on the creationDate. Since the dates are in the ISO format, you can do a string comparison using localeCompare. If the date is in some other format, you could do
new Date(a.creationDate) - new Date(b.creationDate)
Use rxjs map and lodash groupBy.
of(response).pipe(
map(response => _groupBy(moveToFirst(response, item => item.principal === true)), 'commonId')
);
Where moveToFirst is a custom method to move the required item to Index 0.
I want to remove all the null values between the first number and the end number.
My code seems far too complicated.
Love to see some more flexible minds at it.
let values = [null, null, null, 1, 2, null, 3, null, 4, null, null, 5, 6, 7, null, null, null, null];
let startIndex = values.findIndex(n => (n !== null))
let endIndex = values.length - 1;
for ( ; endIndex > 0; endIndex--) {
if (values[endIndex] !== null) break;
}
let arrayCopy = values.slice();
for(let i = endIndex; i > startIndex; i--) {
if (values[i] === null) {
arrayCopy.splice(i, 1);
}
}
console.log(arrayCopy)
Quick and dirty, sure it can be done better
var values = [null, null, null, 1, 2, null, 3, null, 4, null, null, 5, 6, 7, null, null, null, null];
var nonNull = values.filter(value => value !== null);
var result = [...values.slice(0, values.indexOf(nonNull[0])), ...nonNull, ...values.slice(values.lastIndexOf(nonNull[nonNull.length - 1]) + 1)];
console.log(result);
I used a filter taking index or null values into account, it is certainly clearer IMO.
If your array is "very large", it might be interesting to find another way to compute the endIndex, but if you don't have performance problems, I think you can keep this part of your code as it is.
let values = [null, null, null, 1, 2, null, 3, null, 4, null, null, 5, 6, 7, null, null, null, null];
let startIndex = values.findIndex(n => (n !== null))
let endIndex = values.length - 1;
for ( ; endIndex > 0; endIndex--) {
if (values[endIndex] !== null) break;
}
let arrayCopy = values.filter((v, i) => i < startIndex || i > endIndex || v !== null);
console.log(arrayCopy)
This approach use reduce function to find the number of nulls in the at the start and at the end of the array, and then to add counted nulls before and after the non null elements.
let values = [null, null, null, 1, 2, null, 3, null, 4, null, null, 5, 6, 7, null, null, null, null];
var reduceFn = function(a,b){
if (!a.finished && b === null){
a.nullCount++;
}
if (b !== null){
a.finished = true;
}
return a;
};
var start = {finished : false, nullCount:0};
values.reduce(reduceFn,start);
var end = {finished : false, nullCount:0};
values.slice().reverse().reduce(reduceFn,end);
result = Array(start.nullCount).fill(null);
result.push.apply(result,values.filter(v => v !== null));
result.push.apply(result,Array(end.nullCount).fill(null));
console.log(result)
I have array and I want to arrange that to object array structure base on same string before dot, I want to create an object array structure to make it editable, so i can fill the value of each data on my array
var arr = ["data",
"data.cell",
"data.cell.celltiming",
"data.cell.celltiming.0",
"data.cell.celltiming.1",
"data.cell.earfcn",
"data.cell.pci",
"data.cell.rsrp",
"data.cell.rsrp.0",
"data.cell.rsrp.1",
"data.cell.rsrp.2",
"data.cell.rsrq",
"data.cell.rsrq.0",
"data.cell.rsrq.1",
"data.cell.rsrq.2",
"data.cell.sinr",
"data.cell.sinr.0",
"data.cell.sinr.1",
"data.cells",
"data.cells.0",
"data.cells.0.ch",
"data.cells.0.ecno",
"data.cells.0.r99",
"data.cells.0.rscp",
"data.cells.0.sc",
"data.cells.1",
"data.cells.1.ch",
"data.cells.1.ecno",
"data.cells.1.r99",
"data.cells.1.rscp",
"data.cells.1.sc",
"data.cells.2",
"data.cells.2.ch",
"data.cells.2.ecno",
"data.cells.2.r99",
"data.cells.2.rscp",
"data.cells.2.sc",
"data.cells.3",
"data.cells.3.ch",
"data.cells.3.ecno",
"data.cells.3.r99",
"data.cells.3.rscp",
"data.cells.3.sc",
"data.id",
"data.mac",
"data.plmn",
"data.rssi",
"data.time",
"deviceID",
"time"]
how can i arrange that to become object array structure
var arr = [ "data": {
"plmn": "",
"id": "",
"time": '',
"cell": {
"rsrp": [
0,
1,
2
],
"rsrq": [
0,
1,
2
],
"earfcn": '',
"pci": '',
"celltiming": [
0,
1
],
"sinr": [
0,
1
]
},
"mac": ""
},
"time": '',
"deviceID": ""]
I want to create an object array so i can fill the value of each key
I've used the following:
Array.prototype.reduce(), accumulating over an empty object {},
A reference (ref) to the accumulator object,
String.prototype.split() to extract individual keys (substrings) from the current string in the array,
Iterating over the keys to progress along the key "chain",
a. If a key doesn't already exist in the accumulator object, create an object at that key, i.e. if (!ref[key]) ref[key] = {}
b. Continue to traverse the accumulator object by re-setting the reference (ref), i.e. ref = ref[key]
Move to the next string in the original array
var arr = ["data",
"data.cell",
"data.cell.celltiming",
"data.cell.celltiming.0",
"data.cell.celltiming.1",
"data.cell.earfcn",
"data.cell.pci",
"data.cell.rsrp",
"data.cell.rsrp.0",
"data.cell.rsrp.1",
"data.cell.rsrp.2",
"data.cell.rsrq",
"data.cell.rsrq.0",
"data.cell.rsrq.1",
"data.cell.rsrq.2",
"data.cell.sinr",
"data.cell.sinr.0",
"data.cell.sinr.1",
"data.cells",
"data.cells.0",
"data.cells.0.ch",
"data.cells.0.ecno",
"data.cells.0.r99",
"data.cells.0.rscp",
"data.cells.0.sc",
"data.cells.1",
"data.cells.1.ch",
"data.cells.1.ecno",
"data.cells.1.r99",
"data.cells.1.rscp",
"data.cells.1.sc",
"data.cells.2",
"data.cells.2.ch",
"data.cells.2.ecno",
"data.cells.2.r99",
"data.cells.2.rscp",
"data.cells.2.sc",
"data.cells.3",
"data.cells.3.ch",
"data.cells.3.ecno",
"data.cells.3.r99",
"data.cells.3.rscp",
"data.cells.3.sc",
"data.id",
"data.mac",
"data.plmn",
"data.rssi",
"data.time",
"deviceID",
"time"
]
var obj = arr.reduce((accumulator, currentValue, currentIndex) => {
let ref = accumulator;
currentValue.split(".").forEach(key => {
if (!ref[key]) ref[key] = {}
ref = ref[key];
})
return accumulator;
}, {})
console.log(JSON.stringify(obj, null, "\t"));
This gets you most of the way. Now all you need to do is:
Traverse the object (first pass), replacing empty objects with empty strings, then
arr.forEach(chain => { // first pass, change empty objects to empty strings
let ref = obj;
chain.split(".").forEach(key => {
if (Object.keys(ref[key]).length === 0) {
ref[key] = ''
} else {
ref = ref[key]
}
})
})
Traverse the object (second pass), checking when all of the keys of an object are numbers and all of the values are empty strings, and replacing this object with an array of the keys.
function keysAreNumbersAndValuesAreEmptyStrings(object) {
let entries = Object.entries(object);
for (let i = 0; i < entries.length; i++) {
let key = entries[i][0], value = entries[i][1];
if(isNaN(Number(key)) || typeof value !== "string" || value.length !== 0) return false;
}
return true;
}
arr.forEach(chain => { // second pass, change objects whose keys are numbers to an array of those keys
let ref = obj;
chain.split(".").forEach(key => {
if (typeof ref[key] === "object" && keysAreNumbersAndValuesAreEmptyStrings(ref[key])) {
ref[key] = Object.keys(ref[key]).map(val => Number(val));
} else {
ref = ref[key]
}
})
})
Complete solution: https://jsfiddle.net/s2attatz/1/
var arr = ["data",
"data.cell",
"data.cell.celltiming",
"data.cell.celltiming.0",
"data.cell.celltiming.1",
"data.cell.earfcn",
"data.cell.pci",
"data.cell.rsrp",
"data.cell.rsrp.0",
"data.cell.rsrp.1",
"data.cell.rsrp.2",
"data.cell.rsrq",
"data.cell.rsrq.0",
"data.cell.rsrq.1",
"data.cell.rsrq.2",
"data.cell.sinr",
"data.cell.sinr.0",
"data.cell.sinr.1",
"data.cells",
"data.cells.0",
"data.cells.0.ch",
"data.cells.0.ecno",
"data.cells.0.r99",
"data.cells.0.rscp",
"data.cells.0.sc",
"data.cells.1",
"data.cells.1.ch",
"data.cells.1.ecno",
"data.cells.1.r99",
"data.cells.1.rscp",
"data.cells.1.sc",
"data.cells.2",
"data.cells.2.ch",
"data.cells.2.ecno",
"data.cells.2.r99",
"data.cells.2.rscp",
"data.cells.2.sc",
"data.cells.3",
"data.cells.3.ch",
"data.cells.3.ecno",
"data.cells.3.r99",
"data.cells.3.rscp",
"data.cells.3.sc",
"data.id",
"data.mac",
"data.plmn",
"data.rssi",
"data.time",
"deviceID",
"time"
]
var obj = arr.reduce((accumulator, currentValue, currentIndex) => {
let ref = accumulator;
currentValue.split(".").forEach(key => {
if (!ref[key]) ref[key] = {}
ref = ref[key];
})
return accumulator;
}, {})
arr.forEach(chain => { // first pass, change empty objects to empty strings
let ref = obj;
chain.split(".").forEach(key => {
if (Object.keys(ref[key]).length === 0) {
ref[key] = ''
} else {
ref = ref[key]
}
})
})
function keysAreNumbersAndValuesAreEmptyStrings(object) {
let entries = Object.entries(object);
for (let i = 0; i < entries.length; i++) {
let key = entries[i][0], value = entries[i][1];
if(isNaN(Number(key)) || typeof value !== "string" || value.length !== 0) return false;
}
return true;
}
arr.forEach(chain => { // second pass, change objects whose keys are numbers to an array of those keys
let ref = obj;
chain.split(".").forEach(key => {
if (typeof ref[key] === "object" && keysAreNumbersAndValuesAreEmptyStrings(ref[key])) {
ref[key] = Object.keys(ref[key]).map(val => Number(val));
} else {
ref = ref[key]
}
})
})
console.log(JSON.stringify(obj, null, "\t"));
/*
{
"data": {
"cell": {
"celltiming": [
0,
1
],
"earfcn": "",
"pci": "",
"rsrp": [
0,
1,
2
],
"rsrq": [
0,
1,
2
],
"sinr": [
0,
1
]
},
"cells": {
"0": {
"ch": "",
"ecno": "",
"r99": "",
"rscp": "",
"sc": ""
},
"1": {
"ch": "",
"ecno": "",
"r99": "",
"rscp": "",
"sc": ""
},
"2": {
"ch": "",
"ecno": "",
"r99": "",
"rscp": "",
"sc": ""
},
"3": {
"ch": "",
"ecno": "",
"r99": "",
"rscp": "",
"sc": ""
}
},
"id": "",
"mac": "",
"plmn": "",
"rssi": "",
"time": ""
},
"deviceID": "",
"time": ""
}
*/