var asdf:Array = [ [1,1] ];
trace( asdf.indexOf( [1,1] ) ); // -1
Why can't indexOf() find the [1,1] array?
Here is a little function I wrote a while ago that works great. I included a lot of comments and an example search/function to output the results.
// set up a multidimensional array that contains some data
var myArray:Array = new Array();
myArray.push(["granola","people... are great"," 4 ","10"]);
myArray.push(["bill","orangutan","buster","keaton"]);
myArray.push(["steve","gates","24","yes, sometimes"]);
myArray.push(["help","dave","jobs","hal"]);
// here we set up some properties on the array object to hold our search string and our results
myArray.myTarget = "steve";
myArray.myResults = [];
// now we call the search
myArray.forEach(multiSearch);
// this is the function that does all the heavy lifting....
function multiSearch(element:*, index:int, array:Array)
{
// see if we have a match in this array and pass back its index
for(var i:* in element)
{
if( element[i].indexOf( array.myTarget ) > -1 )
{
var tempArray:Array = array.myResults;
tempArray.push([index,i]);
array.myResults = tempArray;
}
}
}
// -------------------------------------------------------------------------------
// all the code below is OPTIONAL... it is just to show our results
// in the output window in Flash so you know it worked....
var printArray:Array = myArray.myResults;
for(var i:* in printArray)
{
trace("TARGET FOUND #: "+printArray[i][0]+", "+printArray[i][1]+" = "+myArray[ printArray[i][0] ][ printArray[i][1] ]);
}
// -------------------------------------------------------------------------------
It fails because when you do a [x,y] you are creating a new array, adsf contains one array and indexOf search for another one.
try:
trace([1,1] == [1,1]);
You will see that it prints false, since array are compare by reference.
One quick indexOf function, arrange it to suit your needs:
function isElmEquals(e1:*, e2:*):Boolean {
return (e1==e2);
}
function isArrayEquals(a1:Array, a2:Array):Boolean {
if (a1==a2)
return true;
if ((a1==null) || (a2==null)) {
return false;
}
if (a1.length!=a2.length)
return false;
for (var i:int=0;i<a1.length;i++){
if (!isElmEquals(a1[i], a2[i]))
return false;
}
return true;
}
function indexOf(value:Array, into:Array):int{
var i:int = -1;
into.some(
function(item:*, index:int, array:Array):Boolean {
if (isArrayEquals(item as Array, value)) {
i = index;
return true;
}
return false;
}
);
return i;
}
var i:int=indexOf([1,1], [[-1,1], [0,1], [1,1], [1,-1]]);
trace(i);
var j:int=indexOf([1,2], [[-1,1], [0,1], [1,1], [1,-1]]);
trace(j);
this works. probably because the inner array is typed.
var qwer:Array = [1,1];
var asdf:Array = [qwer];
trace( asdf.indexOf( qwer ) ); // 0
Related
I have an Excel file with the following content:
Inside my component.ts, I extract the Excel's content as follow:
var testUrl= "excel.xlsx";
var oReq = new XMLHttpRequest();
oReq.open("GET", testUrl, true);
oReq.responseType = "arraybuffer";
oReq.onload = function(e) {
var arraybuffer = oReq.response;
var data = new Uint8Array(arraybuffer);
var arr = new Array();
for(var i = 0; i != data.length; ++i){
arr[i] = String.fromCharCode(data[i]);
}
var bstr = arr.join("");
var workbook = XLSX.read(bstr, {type:"binary"});
var first_sheet_name = workbook.SheetNames[0];
var worksheet = workbook.Sheets[first_sheet_name];
var json = XLSX.utils.sheet_to_json(workbook.Sheets[workbook.SheetNames[0]], {header:1, raw:true});
var jsonOut = JSON.stringify(json);
console.log("test"+jsonOut);
}
oReq.onerror = function(e) {
console.log(e);
}
oReq.send();
XLSX.utils.sheet_to_json will format JSON as follow:
However, I would like the JSON to be as follow:
Most probably I would need to manually create the JSON, but can anyone help me point to the direction on how I can accomplish this?
In your case we need to modify the JSON data by looping over XLSX.utils.sheet_to_json JSON object:
// This object will contain the data in the format we want
var finalObj = { "object": []};
// Variables to track where to insert the data
var locIndex, firstCondIndex, secondCondIndex,
lockey, firstCondKey, secondCondkey;
// We need to initialize all indexes to -1 so that on first time we can get 0, as arrays start with 0 in javascript
locIndex = -1;
// here obj is XLSX.utils.sheet_to_json
obj.object.map((value, index) => {
// we don't want to consider name of columns which is first element of array
if(!index) return;
// Go inside only if not null
if(value[0]) {
// For Location
finalObj.object.push(createObj(value[0]));
locIndex++;
// We also need to store key names to push it's children
lockey = value[0];
firstCondIndex = -1;
}
if(value[1]) {
// For First Condition
finalObj.object[locIndex][lockey].push(createObj(value[1]));
firstCondIndex++;
firstCondKey = value[1];
secondCondIndex = -1;
}
if(value[2]) {
// For Second Condition
finalObj.object[locIndex][lockey][firstCondIndex][firstCondKey].push(createObj(value[2]));
secondCondIndex++;
secondCondkey = value[2];
}
if(value[3]) {
// For Products
// We just push the string
finalObj.object[locIndex][lockey][firstCondIndex][firstCondKey][secondCondIndex][secondCondkey].push(value[3]);
}
});
function createObj(val) {
// We need to initialize blank array so we can push the children of that element later on
var obj = {};
obj[val] = [];
return obj;
}
console.log(finalObj);
Can someone help explain the logic used in the JavaScript code here?
The code below checks to see if two strings are anagrams of each other, but I don't understand the method being used to check the string.
Thanks.
<script type="text/javascript">
$(document).ready(function() {
var anagram = function(str1, str2){
if (str1.length !== str2.length) {
return false;
}
var sortstr1 = str1.split('').sort().join('');
var sortstr2 = str2.split('').sort().join('');
return (sortstr1 === sortstr2);
}
$('.AnagramChecker').on('click', function(e) {
e.preventDefault();
if($('#string1').val() == '') {
$('#string1').addClass('error');
if($('#string2').val() == '') {
$('#string2').addClass('error');
}
$('.results').empty();
$('.results').hide();
} else {
$('#string1').removeClass('error');
if($('#string2').val() == '') {
$('#string2').addClass('error');
$('.results').empty();
$('.results').hide();
} else {
$('#string2').removeClass('error');
var isAnagram = anagram($('#string1').val(), $('#string2').val());
$('#string1').val('');
$('#string2').val('')
$('.results').show();
$('.results').empty().append('Anagram is: ' + isAnagram);
}
}
});
});
</script>
Both strings are being split down into arrays of their individual characters, which are then sorted alphabetically and joined again into strings. The strings are then compared, and if they are the same, are anagrams of one another.
function anagrams(str1,str2){
//spliting string into array
let arr1 = str1.split("");
let arr2 = str2.split("");
//verifying array lengths
if(arr1.length !== arr2.length){
return false;
}
//creating objects
let frqcounter1={};
let frqcounter2 ={};
// looping through array elements and keeping count
for(let val of arr1){
frqcounter1[val] =(frqcounter1[val] || 0) + 1;
}
for(let val of arr2){
frqcounter2[val] =(frqcounter2[val] || 0) + 1;
}
console.log(frqcounter1);
console.log(frqcounter2);
//loop for every key in first object
for(let key in frqcounter1){
//if second object does not contain same frq count
if(frqcounter2[key] !== frqcounter1[key]){
return false;
}
}
return true;
}
anagrams('anagrams','nagramas');
function compare(a1,a2){
if(a1.length != a2.length){
return false
}
var f1 = {}, f2 ={};
for(var a of a1){
f1[a] = ++f1[a] || 1
}
for(var a of a2){
f2[a] = ++f2[a] || 1
}
for(var key in f1){
if(!(key in f2)){
return false
}
if(f1[key] != f2[key]) {
return false
}
}
return true
}
I am using the following functions on a library and then calling them like this. The issue with the code is that I am not able return the values from the code below:
Would be great if some one suggests a way to return the value back to my test. (I will post the full working code once this is solved). I have not worked with promises so if some one can suggest a solution that be great!
Resolved this!!! check my answer:
My Testcase
iit("Should Find the OrderID and update task and submit", function () {
var job_id_data= lib.getTestData('MYPROJ_TESTCASE_001'); //Problem area
console.log(job_id_data);
element(by.xpath('//input[#type=\'search\']')).sendKeys(job_id_data);
//Do other stuff
}
The below code in my function (lib) needs to return a promise, and I don't know how to do that :(
csvConverter.on("end_parsed",function(jsonObj){
//console.log(jsonObj); //here is your result json object
var foundTestData = getObjects(jsonObj, 'TC', jobreference);
console.log(returnKeyValue ); //I can see this value
returnKeyValue = getValues(foundTestData, 'JOBID'); // I cannot return this??
});
Full Not working code ...Code
var lib = require('./lib/library.js');
iit("should go to logout page", function () {
var id_data= lib.getTestData('Test.3');
//plan to use this value in my tests
});
//Library
function getTestData(jobreference) {
//Converter Class
var Converter=require("csvtojson").core.Converter;
var fs=require("fs");
var csvFileName="C:\\TestData.csv";
var fileStream=fs.createReadStream(csvFileName);
//new converter instance
var param={};
var csvConverter=new Converter(param);
var returnKeyValue="";
var result = {};
//This requires a code change:
csvConverter.on("end_parsed",function(jsonObj){
//console.log(jsonObj); //here is your result json object
var foundTestData = getObjects(jsonObj, 'TC', jobreference);
console.log(returnKeyValue ); //I can see this value
returnKeyValue = getValues(foundTestData, 'JOBID'); // I cannot return this??
});
//read from file
fileStream.pipe(csvConverter);
return returnKeyValue;
}
function getValues(obj, key) {
var objects = [];
for (var i in obj) {
if (!obj.hasOwnProperty(i)) continue;
if (typeof obj[i] == 'object') {
objects = objects.concat(getValues(obj[i], key));
} else if (i == key) {
objects.push(obj[i]);
}
}
return objects;
}
function getObjects(obj, key, val) {
var objects = [];
for (var i in obj) {
if (!obj.hasOwnProperty(i)) continue;
if (typeof obj[i] == 'object') {
objects = objects.concat(getObjects(obj[i], key, val));
} else
//if key matches and value matches or if key matches and value is not passed (eliminating the case where key matches but passed value does not)
if (i == key && obj[i] == val || i == key && val == '') { //
objects.push(obj);
} else if (obj[i] == val && key == ''){
//only add if the object is not already in the array
if (objects.lastIndexOf(obj) == -1){
objects.push(obj);
}
}
}
return objects;
}
Managed to resolve this :) with some help from my colleague (thanks :))
This post here helped me get quickly to the point
http://know.cujojs.com/tutorials/promises/creating-promises
Solution is I updated the function to the following, which basically works with Protractor Promises. Which is great.
function getTestData(jobreference) {
var Converter=require("csvtojson").core.Converter;
var fs=require("fs");
var csvFileName="TESTJOB.csv";
var fileStream=fs.createReadStream(csvFileName);
var csvConverter=new Converter(param);
//new converter instance
var param={};
var csvConverter=new Converter(param);
var d = protractor.promise.defer();
csvConverter.on("end_parsed",function(jsonObj){
var foundTestData = getObjects(jsonObj, 'TCaseID', jobreference);
returnKeyValue = getValues(foundTestData, 'ID');
console.log(returnKeyValue.toString());
d.fulfill(returnKeyValue.toString());
});
//d.reject("fail!!!!");
fileStream.pipe(csvConverter);
return d.promise;
}
I want merge 2 array collection, where no duplicates are allowed,
var ac1:ArrayCollection = new ArrayCollection([ {s:"4",e:"8"}, {s:"9",e:"10"}, ]);
var ac2:ArrayCollection = new ArrayCollection([ {s:"2",e:"3"}, {s:"4",e:"8"}, {s:"9",e:"10"}, {s:"11",e:"12"}, ]);
how can I do it in efficient way
Thanks,
Errr, I'm not an actionscript guy but it's a classic problem - sort the two arrays in ascending order, then feed them into your third array, always selecting the lowest value from the two source arrays and escaping the write to the destination if what you would write is already at the end of the list - you'll end up with a sorted list of the unique values in the n input arrays
For more properties, use something like:
function equals(o1:Object, o2:Object):Boolean
{
if (o1 == o2) return true;
if (!o1 || !o2) return false;
for (var key:String in o1)
{
if (!(key in o2)) return false;
if (o1[key] != o2[key]) return false;
}
return true;
}
Perhaps this is a good starter.
function equals(o1:Object, o2:Object)
{
return (o1 && o2) && (o1 != o2) && (o1.s != o2.s) && (o1.e != o2.e);
}
function merge(a:Array, b:Array):Array
{
const source = [];
var isContained:Boolean = false;
for (var i:int; i< a.length;i++) {
isContained = false
for (var j:int; j< b.length;j++) {
if (equals(a[i], b[j])) {
isContained = true;
break;
}
}
if (!isContained) {
source.push(a[1]);
}
}
return source.concat(b);
}
i don't understand arrays in functions, but how do you find the matching items given in an array? for example:
var fruit:Array = ["apples", "oranges", "grapes", "oranges", "apples", "grapes"];
how can i get it to show only the number of apples in the array?
Simply, you can do this:
private function getCount(fruitArray:Array, fruitName:String):int {
var count:int=0;
for (var i:int=0; i<fruitArray.length; i++) {
if(fruitArray[i].toLowerCase()==fruitName.toLowerCase()) {
count++;
}
}
return count;
}
var fruit:Array = ["apples", "oranges", "grapes", "oranges", "apples", "grapes"];
var appleCount=getCount(fruit, "apples"); //returns 2
var grapeCount=getCount(fruit, "grapes"); //returns 2
var orangeCount=getCount(fruit, "oranges"); //returns 2
Depending on how many items are in the array, and how often you want to search for different items, it can get very costly to have a for loop iterate over the entire array, every time you want to count things (which would happen if you did what the other two answers suggest). You might want to have a count function that iterates over the array just once, and returns a list of counters, instead of a single number:
function countItems( arr:Array ) : Object {
var counts : Object = {};
for each ( var item : String in arr ) {
if (counts.hasOwnProperty(item)) counts[item]++;
else counts[item] = 1;
}
return counts;
}
var fruit:Array = ["apples", "oranges", "grapes", "oranges", "apples", "grapes"];
var counts : Object = countItems(fruit);
trace (counts["apples"]); // => 2
trace (counts["oranges"]); // => 2
trace (counts["grapes"]); // => 2
function countOccurrences( haystack, needle ){
var index : int = -1;
var counter : int = -1;
do{
counter++;
index = haystack.indexOf( needle, index + 1 );
}while( index >= 0 );
return counter;
}
var fruit:Array = ["apples", "oranges", "grapes", "oranges", "apples", "grapes"];
trace( countOccurrences( fruit, "apples" ) ); //outputs '2'
var stringToSearch:String = "apples";
var pattern:RegExp = new RegExp(/\b\b/.source+stringToSearch, "g");
var matches:Array = fruit.toString().match(pattern);
//
trace(matches.length);
Disclaimer: don't use this if you have many elements in your array (eg. fruit.length>1000): it is compact but it can be slower than any other solution posted here. Another thing to point out is that here I'm assuming your "matching items" are "strings".
Try something like
private function makeFilter(filterValue:String):Function {
var fn:Function = function (obj:Object, index:int=0, arr:Array=[]):Boolean {
if (String(obj)==filterValue) {
return true;
}
return false;
}
return fn;
}
//somewhere else:
var filterFunction:Function = makeFilter('apples');
var appleCount:int = fruit.filter(filterFunction).length;
FYI, more about this approach: http://www.gasi.ch/blog/functional-actionscript-1/
var matches = 0
var arrayMatcher = (array1, array2) => {
for (let i = 0; i <= array1 - 1; i++) {
var myFirstItem = array1[i];
for (a = 0; a <= array2.length - 1; a++) {
var mySecondItem = array2[a];
if (mySecondItem === myFirstItem) {
matches += 1;
}
}
}
return matches;
}
I used this to find matches in a list of a patient's symptoms with a list of common symptoms for a certain disease and it worked for me. You could give it a try! :)