I have two ArrayCollection and I want to merge them into one...
arr1 =
[0] -> month = 07
tot_err = 15
[1] -> month = 08
tot_err = 16
[2] -> month = 09
tot_err = 17
arr2 =
[0] -> month = 07
tot_ok = 5
[1] -> month = 08
tot_ok = 6
[2] -> month = 09
tot_ok = 7
I would like to have this array
arr3 =
[0] -> month = 07
tot_err = 15
tot_ok = 5
[1] -> month = 08
tot_err = 16
tot_ok = 6
[2] -> month = 09
tot_err = 17
tot_ok = 7
How can I do it?
EDIT:
I did this solution:
private function mergeArrays(a:ArrayCollection, b:ArrayCollection):ArrayCollection
{
for (var i:int=0;i<a.length;i++)
for each(var item:Object in b)
{
if( a[i].month == item.month){
a[i].tot_err = item.tot_err;
}
}
return a;
}
But there is an important problem, if array2 (b) has a item.month that there isn't in the array1 (a) the value is lost...
private function mergeArrays(a:ArrayCollection, b:ArrayCollection):ArrayCollection
{
var result:ArrayCollection = new ArrayCollection();
var months:Dictionary = new Dictionary();
for (var i:int = 0; i < a.length; i++)
{
var mergedItem:Object = new Object();
mergedItem.month = a[i].month;
mergedItem.tot_ok = a[i].tot_ok;
mergedItem.tot_err = null;
for (var j:int = 0; j < b.length; j++)
{
if(a[i].month == b[j].month)
{
mergedItem.tot_err = b[j].tot_err;
}
}
month[mergedItem.month] = true;
result.addItem(mergedItem);
}
// so far we have handled all occurrences between a and b,
// now we need to handle the items from b that are left
for each (var bItem:Object in b)
{
mergedItem = new Object();
mergedItem.month = bItem.month;
mergedItem.tot_err = bItem.tot_err;
mergedItem.tot_ok = null;
if (months[mergedItem.month] == null)
{
month[mergedItem.month] = true;
result.addItem(mergedItem);
}
}
return result;
}
if( a[i].month == item.month){
a[i].tot_err = item.tot_err;
// remove the item from b here. dontknow arraycollection
// should be like b.remove(item);
}
after for loops you can check if "b" still have elements, so you can add them to "a", dont forget to give "b" array objects a default tot_ok value. And another thing if an object in "a" that doesnt have equalivant in "b" you can use this.
private function mergeArrays(a:ArrayCollection, b:ArrayCollection):ArrayCollection
{
var ex:Boolean = true;
for (var i:int=0;i<a.length;i++){
for each(var item:Object in b)
{
if( a[i].month == item.month){
a[i].tot_err = item.tot_err;
ex = true;
}else{
ex = false;
}
}
if(!ex){
// give a default value here.
a[i].tot_err = 0;
}
}
return a;
}
private function mergeArrayCollections(a:ArrayCollection, b:ArrayCollection):ArrayCollection {
var c:ArrayCollection=new ArrayCollection(b.toArray()); //clone b so as not to modify b
//This loop handles all objects common to a and b
for each(var o:Object in a) {
for (var i:int=0; i<c.length; i++) {
var p:Object=c.getItemAt(i);
if(o.month==p.month) {
//if the month is the same then add the property to a
o.tot_ok=p.tot_ok;
c.removeItemAt(i);
break;
}
}
}
//This loop adds the leftover items from c to a
for each(var q:Object in c) {
q.tot_err=-1; //add this so that all objects in a are uniform
a.addItem(q);
}
return a; //Unnecessary return, a will be modified by reference
}
if array2 (b) has a item.month that there isn't in the array1 (a) use addItem() method to add new object to array1 (a) ;
Related
I am having troubles in
Exception: The number of rows in the data does not match the number of rows in the range. The data has 1 but the range has 8. Google Script
function myFunction() {
var s1 = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Staging');
var s2 = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Final');
var values1 = s1.getDataRange().getValues();
var values2 = s2.getDataRange().getValues();
var Avals = s2.getRange("A1:A").getValues();
var Alast = Avals.filter(String).length;
var resultArray = [];
for(var n=0; n < values1.length ; n++)
{
var keep = false;
var counter = 0;
for(var p=0; p < values2.length ; p++)
{
if( values1[n][1] == values2[p][1])
{
keep = true;
break ;
}
}
if(keep == false)
{
resultArray.push([values1[n]]);
//s2.appendRow( values1[n] );
s2.getRange(Alast + 1, 1, values1[n].length, values1[n].length).setValues([values1[n]]);
//s2.getRange(s2.getLastRow() + 1, 1, values1.length, values1[0].length).appendRow( values1[n] );
resultArray = [];
keep = false
}
}
}
I believe you are trying to keep appending a new row to the end of the data on "Final". You should revise you script as shown below. Use resultArray to collect all new rows and save it to spreadsheet once.
function myFunction() {
var s1 = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Staging');
var s2 = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Final');
var values1 = s1.getDataRange().getValues();
var values2 = s2.getDataRange().getValues();
// s2.getDataRange() will get up to the last row of data
var Alast = values2.length;
var resultArray = [];
for(var n=0; n < values1.length ; n++)
{
var keep = false;
var counter = 0;
for(var p=0; p < values2.length ; p++)
{
if( values1[n][1] == values2[p][1])
{
keep = true;
break ;
}
}
if(keep == false)
{
resultArray.push(values1[n]);
keep = false
}
}
if( resultArray.length > 0 ) {
s2.getRange(Alast+1,1,resultArray.length,resultArray[0].length).setValues(resultArray);
}
}
Would like to use information into spreadsheets from a live Google Map (KML data). The code below handle it, but not as fast as required. It must handle up to 10 layers with about 2000 placemarks, line positions and/or polygon positions in the interesting (parameter "restrict") layer (or all layers). The size of the kml (xml) data is therefore often quite large.
Question 1: How (if possible) can caching and/or some other solution be implemented to handle about 2Mb xml data?
Question 2: How can what improvements be implemented to stream line the code, add flexibility to dynamically handle unknown (in advance) number of columns/rows and lower the execution time?
/**
* Fetch a Google Map and write the data to the spreadsheet (URL and layer).
*
* #param {url} input the URL associated with the Google Map (should contain &forcekml=1).
* #param {restrict} input the Layer name you want to restrict the data to.
* #return a range of data depending on the info in the map
* #customfunction
*/
function IMPORTMAP( url, restrict ) {
/* One key only allow 100k
var cache = CacheService.getPublicCache();
var cached = cache.get( "google-maps-xml" );
var cached = cache.getAll('?'); //Unknown keys in advance that also may change from time to time.
if ( cached != null ) {
return cached;
}*/
var txt = UrlFetchApp.fetch( url ).getContentText();
var sheet = SpreadsheetApp.getActiveSheet();
var width = sheet.getMaxColumns();
var height = sheet.getMaxRows();
var xmlDoc = XmlService.parse( txt );
var root = xmlDoc.getRootElement();
var atom = XmlService.getNamespace( 'http://www.opengis.net/kml/2.2' );
var xml2csv = [[height],[10]];
var labels = [], label = '', counter = 0, o = 0;
var documents = root.getChildren( 'Document', atom );
for( var i = 0; i < documents.length; i++ ) {
var Folders = documents[i].getChildren( 'Folder', atom );
for( var j = 0; j < Folders.length && j <= height; j++ ) {
if( Folders[j].getChild( 'name', atom ).getValue() == restrict ) {
var Placemarks = Folders[j].getChildren( 'Placemark', atom );
for( var k = 0; k < Placemarks.length; k++ ) {
var nodes = Placemarks[k].getChildren();
for( var l = 0; l < nodes.length; l++ ) {
var data = nodes[l].getChildren();
if( data.length > 0 ) {
for( var m = 0; m < data.length && counter <= width; m++ ) {
if( data[m].getAttribute( 'name' ) != null ) {
if( labels[ data[m].getAttribute( 'name' ).getValue().trim() ] == null ) {
labels[ data[m].getAttribute( 'name' ).getValue().trim() ] = counter;
xml2csv[ 0 ][ counter++ ] = data[m].getAttribute( 'name' ).getValue().trim();
}
}
if( data[m].getChild( 'value', atom ) != null ) {
xml2csv[ k + 1 ][ labels[ data[m].getAttribute( 'name' ).getValue().trim() ] ] = data[m].getChild( 'value', atom ).getValue().trim();
} else {
o = labels[ data[m].getName().trim() ];
if( o == null ) {
labels[ data[m].getName().trim() ] = counter;
o = counter;
xml2csv[ 0 ][ counter++ ] = data[m].getName().trim();
}
if( xml2csv[ k + 1 ] == null ) {
xml2csv[ k + 1 ] = new Array( counter );
}
xml2csv[ k + 1 ][ labels[ data[m].getName().trim() ] ] = data[m].getValue().trim();
}
}
} else {
if( label == '' )
label = nodes[l].getName().trim();
o = labels[ nodes[l].getName().trim() ];
if( o == null ) {
labels[ nodes[l].getName().trim() ] = counter;
o = counter;
xml2csv[ 0 ][ counter++ ] = nodes[l].getName().trim();
}
if( xml2csv[ k + 1 ] == null ) {
xml2csv[ k + 1 ] = new Array( counter );
}
xml2csv[ k + 1 ][ o ] = nodes[l].getValue().trim();
}
}
}
}
}
}
//cache.putAll( xml2csv, 1500 ); // cache for 25 minutes
return xml2csv;
}
Please note that code only handle specific kml data in its current form and may not be suitable for a wider audience.
//array
var boxs: Array = new Array
boxs[0] = [b1.x = 307.95 , b1.y = 202]
boxs[1] = [b2.x = 233.95 , b2.y = 202]
boxs[2] = [b3.x = 159.95 , b3.y = 202]
//varable
var oldg:Number = 0
//random number
oldg = Number(Math.floor(Math.random()*boxs.length))
Naive approach:
public function Main()
{
const array:Array = [1,2,3,4,5,6,7];
trace(array);
// 1,2,3,4,5,6,7
swapTwoRandomElements(array);
trace(array);
// 1,2,3,6,5,4,7
}
private function swapTwoRandomElements(input:Array):void
{
const indices:Array = [];
for (var i:int = 0; i < input.length; i++)
{
indices.push(i);
}
const indexFirst:int = indices[int(Math.random() * indices.length)];
indices.splice(indexFirst, 1);
const indexSecond:int = indices[int(Math.random() * indices.length)];
indices.splice(indexSecond, 1);
const tmp:* = input[indexFirst];
input[indexFirst] = input[indexSecond];
input[indexSecond] = tmp;
}
Im trying to make a multidimensional array but I obtain an error ("TypeError: Error #1010: A term is undefined and has no properties.").
var matriz:Array = new Array();
for(var p:Number = 0; p<2;p++ ){
for(var q:Number = 0; q<2;q++ ){
matriz[p][q] = 0;
}
}
what am I doing wrong?
Thanks in advance!
You need to create an array within matriz[p] before you can add an array (or anything else) into it.
You can achieve what you're attempting without errors like this:
var matriz:Array = [];
for(var p:Number = 0; p<2; p++)
{
// Create an array at matriz[p] if undefined.
if(matriz[p] == undefined) matriz[p] = [];
for(var q:Number = 0; q<2; q++)
{
matriz[p][q] = 0;
}
}
Essentially you were trying to do the same as this:
var object:Object = {};
object.nonexistantProperty.value = 10;
What Marty has said is correct, however I prefer removing the if condition and changing the code to the following:
var matriz:Array = [];
for(var p:Number = 0; p<2; p++) {
matriz[p] = [];
for(var q:Number = 0; q<2; q++) {
matriz[p][q] = 0;
}
}
public class cArray
{
private var DIM1CAP:uint=0;
private var DIM2CAP:uint=1;
private var DIM3CAP:uint=2;
private var DIM4CAP:uint=3;
private var DIM5CAP:uint=4;
public function cArray():void
{
// avoid the noid
}
// returns empty array of args.length dimensions
// 1st argument is dim 1 capacity; 2nd is dim 2, etc.
public function getArray ( ... args ):Array
{
var arr = new Array();
if ( paramsNotValid(args) )
{
return null;
}
switch (args.length)
{
case 2:
arr = get2DArray ( args[0], args[1] );
break;
case 3:
arr = get3DArray ( args[0], args[1], args[2] );
break;
case 4:
arr = get4DArray ( args[0], args[1], args[2], args[3] );
break;
case 5:
arr = get5DArray ( args[0], args[1], args[2], args[3], args[4] );
break;
default:
break;
}
return arr;
}
// returns empty 2d array of parameter specified capacity
private function get2DArray ( _1stDimCapacity:uint, _2ndDimCapacity:uint ):Array
{
var arr2d:Array = [];
var arr1d = new Array();
for ( var i:uint=0; i<_1stDimCapacity; i++ )
{
arr1d[_2ndDimCapacity-1] = undefined;
arr2d.push(arr1d);
arr1d = new Array();
}
return arr2d;
}
// returns empty 3d array of parameter specified capacity
private function get3DArray ( dim1Cap:uint,
dim2Cap:uint,
dim3Cap:uint ):Array
{
var arr3d = new Array();
for ( var i:uint=0; i<dim1Cap; i++ )
{
arr3d.push ( get2DArray ( dim2Cap, dim3Cap ) );
}
return arr3d;
}
// returns empty 4d array of parameter specified capacity
private function get4DArray ( dim1Cap:uint,
dim2Cap:uint,
dim3Cap:uint,
dim4Cap:uint):Array
{
var arr4d = new Array();
for ( var i:uint=0; i<dim1Cap; i++ )
{
arr4d.push ( get3DArray ( dim2Cap, dim3Cap, dim4Cap ) );
}
return arr4d;
}
// returns empty 5d array of parameter specified capacity
private function get5DArray ( dim1Cap:uint,
dim2Cap:uint,
dim3Cap:uint,
dim4Cap:uint,
dim5Cap:uint):Array
{
var arr5d = new Array();
for ( var i:uint=0; i<dim1Cap; i++ )
{
arr5d.push ( get4DArray ( dim2Cap, dim3Cap, dim4Cap, dim5Cap ) );
}
return arr5d;
}
//////////////////////////////////////////////////////
private function paramsNotValid ( args:Array ):Boolean
{
if ( args.length<2 || args.length>5 )
{
return true;
}
for ( var i:uint=0; i<args.length; i++ )
{
if ( ! ( args[i]>0 ) )
{
break;
}
}
if ( i < args.length )
{
return true;
}
return false;
}
}
}
public class cMain extends MovieClip
{
var cArr:cArray = new cArray;
public function cMain():void
{
var arr2d:Array;
var arr3d:Array;
var chessBrd_4d:Array;
var arr5d:Array;
// capacity of 10 games; 150 moves/gm; white's mv or black's;
// - piece positions; move in chess notation (index 32 of
// - last dimension); commentary (index 33 of last dimension)
chessBrd_4d = cArr.getArray(10,150,2,34);
// adding data
// - 4th game, 8th move, white's move, positions of pieces
chessBrd_4d[3][7][0][0] = 'd8';
chessBrd_4d[3][7][0][1] = 'b1';
// ...
// - positions of pieces up to last one
// ...
// - last piece pos
chessBrd_4d[3][7][0][31] = 'captured';
// - actual move in chess notation
chessBrd_4d[3][7][0][32] = 'nC4';
// - annotation
chessBrd_4d[3][7][0][33] = 'blocks b pawn, ' +
'opens diag for c1 bishop, ' +
'Justin Beiber is a putz, ' +
'the president is liar'
trace ( 'piece 0 is on square ' + chessBrd_4d[3][7][0][0]);
trace ( 'piece 1 is on square ' + chessBrd_4d[3][7][0][1]);
trace ( ' ... ' )
trace ( 'piece 31 has been ' + chessBrd_4d[3][7][0][31]);
trace ( 'move: ' + chessBrd_4d[3][7][0][32]);
trace ( chessBrd_4d[3][7][0][33]);
/*
trace results:
piece 0 is on square d8
piece 1 is on square b1
...
piece 31 has been captured
move: nC4
blocks b pawn, opens diag for c1 bishop,
Justin Beiber is a putz, the president is liar
*/
/*
trace ( chessBrd_4d.length ); = 10
trace ( chessBrd_4d [ 2 ].length ); = 150
trace ( chessBrd_4d [ 2 ] [ 4 ].length ); = 2
trace ( chessBrd_4d [ 2 ] [ 4 ] [ 1 ].length ); = 34
trace ( chessBrd_4d [ 2 ] [ 4 ] [ 0 ] .length); = 34
*/
}
}
I am able to do this query just fine with the test repository which is In Memory
when I move to the sqlRepository I get this error
Unsupported overload used for query operator 'Intersect'.
I assume it is because sending the query to sql is too complicated for Linq to Sql to do when it is not dealing with the Model.Model.Talent Type. Is there some way around doing a search like this with Intersect?
thanks
public class TalentService : ITalentService
{
ITalentRepository _repository = null;
private IQueryable<Talent> BasicSearch(string searchExpression)
{
IQueryable<Talent> t;
string[] sa = searchExpression.Trim().ToLower().Replace(" ", " ").Split(' ');
t = _repository.GetTalents();
foreach (string s in sa)
{
t = t.Intersect(AddBasicSearch(s), new TalentComparer());
}
return t;
}
private IQueryable<Talent> AddBasicSearch(string s)
{
IQueryable<Talent> t2 = _repository.GetTalents()
.Where(tal => tal.EyeColor.ToString().ToLower().Contains(s)
|| tal.FirstName.ToLower().Contains(s)
|| tal.LastName.ToLower().Contains(s)
|| tal.LanguagesString.ToLower().Contains(s)
);
return t2;
}
}
public class SqlTalentRepository:ITalentRepository
{
public IQueryable<Model.Model.Talent> GetTalents()
{
var tal = from t in _db.Talents
let tLanguage = GetTalentLanguages(t.TalentID)
where t.Active == true
select new Model.Model.Talent
{
Id = t.TalentID,
FirstName = t.FirstName,
LastName = t.LastName,
TalentLanguages = new LazyList<Model.Model.TalentLanguage>(tLanguage),
LanguagesString = t.TalentLanguages.ToLanguageNameString(_LanguageRepository.GetLanguages())
};
return tal ;
}
public IQueryable<Model.Model.TalentLanguage> GetTalentLanguages(int iTalentId)
{
var q = from y in this.talentLanguageList
let Languages = _LanguageRepository.GetLanguages()
where y.TalentId == iTalentId
select new Model.Model.TalentLanguage
{
TalentLanguageId = y.TalentLanguageId,
TalentId = y.TalentId,
LanguageId = y.LanguageId,
Language = Languages.Where(x => x.LanguageId == y.LanguageId).SingleOrDefault()
};
return q.AsQueryable<Model.Model.TalentLanguage>();
}
}
public static class TalentExtensions
{
public static string ToLanguageNameString(this IEnumerable<TalentLanguage> source
, IEnumerable<Model.Model.Language> allLanguages)
{
StringBuilder sb = new StringBuilder();
const string del = ", ";
foreach (TalentLanguage te in source)
{
sb.AppendFormat("{0}{1}", allLanguages
.Where(x => x.LanguageId == te.LanguageID).SingleOrDefault().LanguageName, del);
}
string sReturn = sb.ToString();
if (sReturn.EndsWith(del))
sReturn = sReturn.Substring(0, sReturn.Length - del.Length);
return sReturn;
}
}
public class TestTalentRepository : ITalentRepository
{
IList<Talent> talentList;
public TestTalentRepository(ILanguageRepository _LanguageRepo )
{
this._LanguageRepository = _LanguageRepo;
talentList = new List<Talent>();
talentLanguageList = new List<TalentLanguage>();
for (int i = 0; i < 55; i++)
{
var t = new Talent();
t.Id = i;
t.FirstName = (i % 3 == 0) ? "Ryan" : "Joe";
t.LastName = (i % 2 == 0) ? "Simpson" : "Zimmerman";
AddLanguagesToTestTalent(i, t);
talentList.Add(t);
}
}
private void AddLanguagesToTestTalent(int i, Talent t)
{
IList<Language> Languages = _LanguageRepository.GetLanguages().ToList<Language>();
Random rLanguages = new Random();
int numLanguages = rLanguages.Next(Languages.Count - 1) + 1;
t.TalentLanguages = new LazyList<TalentLanguage>();
for (int j = 0; j < numLanguages; j++)
{
var x = new TalentLanguage();
x.TalentLanguageId = j;
x.TalentId = i;
Random random2 = new Random();
int rand = random2.Next(Languages.Count);
var y = Languages.ElementAtOrDefault(rand);
Languages.RemoveAt(rand);
x.Language = y;
x.LanguageId = y.LanguageId;
t.TalentLanguages.Add(x);
}
}
public IQueryable<Talent> GetTalents()
{
var ts = from t in this.talentList
let tLanguage = GetTalentLanguages(t.Id)
where t.Active == true
select new Model.Model.Talent
{
Id = t.Id,
FirstName = t.FirstName,
LastName = t.LastName,
TalentLanguages = new LazyList<Model.Model.TalentLanguage>(tLanguage),
LanguagesString = t.TalentLanguages.ToLanguageNameString(_LanguageRepository.GetLanguages()),
City = t.City,
};
return ts.AsQueryable<Model.Model.Talent>();
}
public IQueryable<Model.Model.TalentLanguage> GetTalentLanguages(int iTalentId)
{
var q = from y in this.talentLanguageList
let Languages = _LanguageRepository.GetLanguages()
where y.TalentId == iTalentId
select new Model.Model.TalentLanguage
{
TalentLanguageId = y.TalentLanguageId,
TalentId = y.TalentId,
LanguageId = y.LanguageId,
Language = Languages.Where(x => x.LanguageId == y.LanguageId).SingleOrDefault()
};
return q.AsQueryable<Model.Model.TalentLanguage>();
}
}
If you're trying to find entries which match all of those criteria, you just need multiple where clauses:
private static readonly char[] SplitDelimiters = " ".ToCharArray();
private IQueryable<Talent> BasicSearch(string search)
{
// Just replacing " " with " " wouldn't help with "a b"
string[] terms = search.Trim()
.ToLower()
.Split(SplitDelimiters,
StringSplitOptions.RemoveEmptyEntries);
IQueryable<Talent> query = _repository.GetTalents();
foreach (string searchTerm in terms)
{
query = AddBasicSearch(query, searchTerm);
}
return query;
}
private IQueryable<Talent> AddBasicSearch(IQueryable<Talent> query, string s)
{
return query.Where(tal =>
tal.EyeColor.ToString().ToLower().Contains(s)
|| tal.FirstName.ToLower().Contains(s)
|| tal.LastName.ToLower().Contains(s)
|| tal.LanguagesString.ToLower().Contains(s)
);
}