I have 30 string[4] elements which contains user data. I have 30 date generic list collection. How to add each date as 5th element in each one string[] collection?
List<string> _datefromexcel = new List<string> ();
foreach(DataColumn c in dtRow.Table.Columns) {
if (Information.IsDate(c.ColumnName)) {
_datefromexcel.Add(c.ColumnName);
}
}
List<string> newlist = lst.GetRange(startrange, count);
int i = 0;
var query = from s in newlist
let num = i++
group s by num / 4 into g
select g.ToList();
var results = query.ToArray();
foreach(var item in _datefromexcel) {
results.insert(5, item);
}
This is insert all date value after 5th element.
Please advice the best way to insert each date value as 5 element in array collection.
For starters, you won't be able to "insert" anything into an array, since it has a static size. You can add things to a list, however, because a list can dynamically resize itself.
var results = query.ToList();
foreach (var item in _datefromexcel) {
results.Add(item.ToString());
}
If you need to, you can call ToArray after the foreach loop is finished:
return results.ToArray();
You can use for loop instead:
var results = query.ToArray();
for (int i = 0; i < results.Length; i++)
results[i].Add(_datefromexcel[i]);
The LINQ way will be a bit ugly:
var results = query.Zip(_datefromexcel, (l, d) => l.Concat(new[] { d }).ToList()).ToArray();
Related
I am trying to filter the array 'employee_name' consisting of NaNs and one string element, to exclude any element BUT the string. The context is that I have a spreadsheet containing employee's birth dates, and I'm sending an email notification in case there's a birthday two days from today. My variables look like this:
var ss = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Employees');
var range = ss.getRange(2, 1, ss.getLastRow()-1, 1); // column containing the birth dates
var birthdates = range.getValues(); // get the `values` of birth date column
var today = new Date ();
var today = new Date(today.getTime());
var secondDate = new Date(today.getTime() + 48 * 60 * 60 * 1000);
var employee_name = new Array(birthdates.length-1);
And the loop:
for (var i=0;i<=birthdates.length-1;i=i+1){
var fDate = new Date(birthdates[i][0]);
if (fDate.getDate() == secondDate.getDate() &&
fDate.getMonth() == secondDate.getMonth()){
//define variables for outgoing email
for (var j=0; j<=birthdates.length-1;j=j+1){
employee_name[j] = [NaN];
}
employee_name[i] = ss.getRange(i+2,6);
employee_name[i] = employee_name[i].getValues();
}
}
after which the array in question looks like this
Logger.log(employee_name);
[[[Mia-Angelica]], [NaN], [NaN], [NaN], ..., [NaN]]
I have already tried the filter(Boolean), but this isn't working:
employee_name_filtered = employee_name.filter(Boolean);
Logger.log(employee_name_filtered);
returns [[[Mia-Angelica]], [NaN], [NaN], [NaN], ..., [NaN]].
I have also tried filling the non-string array entries with numeric values (instead of NaN) and then apply
employee_name_filtered = employee_name.filter(isFinite);
Logger.log(employee_name_filtered);
returns [[1.0], [2.0], [3.0], ..., [72.0]], so this filter method is working, but then I would need the 'inverse' of that because I want to keep the string.
I need the array within array to store the values at the position of the counter variable where the condition's met (similar to How to store data in Array using For loop in Google apps script - pass array by value).
This is my first time posting a question on SO, so if I overlooked any 'rules' about posting, just let me know and I will provide additional info.
Any help will be appreciated!
EDIT:
what I would like to receive in the end is simply
[[Mia-Angelica]].
The array you are using a 2 dimensional array - meaning it's an array of arrays so the filter method you are using cannot be applied in the same manner.
For this, I suggest you try the below snippet.
function cleanArray() {
var initialArray = [
['Mia-Angelica'],
['Space'],
['2'],
[NaN],
[NaN],
[NaN],
[NaN]
];
var finalArray = [];
for (let i = 0; i < initialArray.length; i++) {
var midArray = initialArray[i].filter(item => (Number.isFinite(item) && item.id !== 0) || !Object.is(item, NaN));
finalArray.push(midArray);
}
console.log(finalArray.filter(item => item != ''));
}
Note
Please bear in mind that getValues will return an Object[][] which is a two-dimensional array of values.
Reference
Apps Script Range Class;
Array.prototype.filter().
I have a tableView(purchases cart), which include magazines in multiple sections. In section, we can see cells with stuff from magazine. In the cell, I did display UILabel(price), UILabel(count) and UILabel with summary price (item * count) in one cell. Also, we can see two buttons (plus and minus), for changing count of item. Example -
var count: Float = Float(cell.countLabel.text!)!
guard Int(count) > 1 else { return }
var shortPrice = cell.newPrice.text
shortPrice?.removeLast(2)
let floatPrice = Float(shortPrice!)
count -= 1
let newSumShortPrice = floatPrice! * count
cell.countLabel.text = String(Int(count))
cell.summPrice.text = "\(newSumShortPrice) ₽"
But changes didn't work with an array.
The strcuct of my model -
struct ViewModel {
var name: String?
var offers: [Offers]?
}
struct Offers : Mappable {
var count : Int?
var fullPrice : String?
var shortPrice : String?
}
var purchasesViewModel = [PurchaseList.Fetch.ViewModel]()
I know, that I must pass changed data (count) to my array and use method tableView.reloadData(). But I can't, because I don't know how to do that.
How I can transfer new count value (check struct Offers) to array purchasesViewModel?
You can go to the index of the array and delete the particular data(old data) from purchasesViewModel and recreate new data and insert it on that index. I hope this will work.
I'm trying to alter some code from a tutorial on how to remove duplicate rows from my sheet. The code works great for straight values, but some of my rows have cells with hyperlink formulas that I don't want to lose.
I think I need to make the spreadsheet data as an array, rather than just using getValues. It's been a long time since I've had to make an array, so I'm struggling with the best way to do this. I'll need for loops to populate the array and if statements to either get values or formulas depending on the row.
Here's the remove duplicates code that removes rows if the cell in column A and B match another row:
/**
* Removes duplicate rows from the current sheet.
*/
function removeDuplicates() {
var sheet = SpreadsheetApp.getActiveSheet();
var data = sheet.getDataRange().getValues();
var newData = [];
for (var i in data) {
var row = data[i];
var duplicate = false;
for (var j in newData) {
if(row[0] == newData[j][0] && row[1] == newData[j][1]){
duplicate = true;
}
}
if (!duplicate) {
newData.push(row);
}
}
sheet.clearContents();
sheet.getRange(1, 1, newData.length, newData[0].length).setValues(newData);
}
So instead of just using one line to set the data variable, I need to build the array with values and formulas where appropriate. Otherwise, I lose my hyperlinks. How do I do this?
Edit: This question was solved by using an answer to another question. The questions' contexts are not the same, and the other question did not show up in any of my research, so I believe my question is not a duplicate.
Thanks to the comment by TheMaster, I was able to solve this. Here's the original "Remove Duplicates" tutorial, and here's the question TheMaster directed me to to find the solution.
My final code:
/**
* Removes duplicate rows from the current sheet.
*/
function removeDuplicates() {
var sheet = SpreadsheetApp.getActiveSheet();
var range = sheet.getDataRange();
var newData = [];
var data = range.getValues();
data = range.getFormulas().map(function(e, i) {//i=index of row(e)
return e.map(function(f, j) {//j = index of column(f)
return f === "" ? data[i][j] : f;
});
});
for (var i in data) {
var row = data[i];
var duplicate = false;
for (var j in newData) {
if(row[0] == newData[j][0] && row[1] == newData[j][1]){
duplicate = true;
}
}
if (!duplicate) {
newData.push(row);
}
}
sheet.clearContents();
sheet.getRange(1, 1, newData.length, newData[0].length).setValues(newData);
}
I'm not sure whether there is a simply answer to this but I am assuming there isn't, hence I'm here.
Basically, I want to run a very simple high score table which keeps track of the high scores of a game, but also displays the correct names beside each scores.
This is all easy but I want to be able to do this with just the one array.
For example, I have this code:
var d:Array;
var e:Array;
d = "827-Harry".split("-");
d.push("918-John".split("-"));
trace(d)
Which correctly results this trace:
827,Harry,918,John
My question is, how can I use Array.sort() (or similar) in such a way that the following is produced:
d = 918, John, 827, Harry
It can't be specific to this example. That is, it needs to work with custom names and dynamic scores.
Cheers in advance!
Harry.
create an associative array and use sortOn():
var highscores:Array = new Array();
highscores.push({score: 827, player: "John"});
highscores.push({score: 918, player: "Harry"});
highscores.sortOn("score", Array.DESCENDING | Array.NUMERIC);
for (var i:int = 0; i < highscores.length; i++)
{
trace(highscores[i].score, highscores[i].player);
}
Wouldn't recommend you store your high scores like that but I don't know your reasons so here's exactly how to do what you want.
public function sortArray(arrUnsorted:Array):Array
{
var arrLocal:Array = new Array();
var arrSorted:Array = new Array();
for (var i:int = 0; i < arrUnsorted.length; i += 2)
{
arrLocal.push( { score:int(arrUnsorted[i]), name:arrUnsorted[i + 1] } );
}
arrLocal.sortOn("score", Array.DESCENDING | Array.NUMERIC)
for each(var obj:Object in arrLocal)
{
arrSorted.push(String(obj.score), obj.name);
}
return arrSorted;
}
Then it's as simple as:
var arrUnsorted:Array = ["827", "Harry", "918", "John"];
var arrSorted:Array = sortArray(arrUnsorted);
trace(arrSorted); // 918,John,827,Harry
Hope this is what you're after.
I have an ActionScript 3 array that lists pairs of items like this:
pairs[0] = Array('ItemA', 'ItemB');
pairs[1] = Array('ItemA', 'ItemC');
pairs[2] = Array('ItemC', 'ItemD');
pairs[3] = Array('ItemC', 'ItemE');
pairs[4] = Array('ItemF', 'ItemG');
pairs[5] = Array('ItemF', 'ItemH');
And I need to loop over the array in some way to find all overlapping pairs (any pairs that share common pairs).
For example, ItemA is paired with ItemB and ItemC, so they belong in a group together. ItemC is also paired with ItemD and ItemE so they also need to be a part of the first group.
ItemF, ItemG and ItemH do not overlap with any of the items fromt he first group, so they need to be put into their own group.
The resulting array would need to be something like:
groups[0] = Array('ItemA', 'ItemB', 'ItemC', 'ItemD', 'ItemE');
groups[1] = Array('ItemF', 'ItemG', 'ItemH');
Thanks for any help and suggestions!
Edit:
A little bit of a back story; I'm trying to group together movie clips that overlap each other in 2D to create groups or clusters (might be a better word).
So if I have 3 movieclips on the stage and ClipA overlaps with ClipB and ClipB overlaps ClipC (but ClipA doesn't directly overlap ClipC) they should all be grouped together as they are all a part of the same cluster. This way should a new clip overlap any single item in a cluster, it will be added to that group's array.
I've already got the code worked out to find overlapping elements which is producing this pairs list, now I need to condense it into tidy groups.
An algorithm like the example below should work.
NOTE: This is not the most efficient or concise way to write this code (it's certainly more repetitive than it needs to be), but I wanted to keep it clear and simple for this example. [Also, I haven't tested this code--it's presented as pseudo-code only--so if you find an error, please just let me know, and I'll fix it]
var idx:Object = new Object;
var groups:Array = new Array();
for( var i:int = 0; i<pairs.length; ++i ) {
var onePair:Array = pairs[i];
// which groups do the two items belong to?
var g1:Array = idx[onePair[0]];
var g2:Array = idx[onePair[1]];
if( !g1 ) {
// if item #1 is not yet in a group, then add it to item #2's
// existing group, or if neither group exists yet, just create a new one
g1 = g2;
if( !g1 ) {
g1 = [];
groups.push(g1);
}
g1.push( onePair[0] );
// ensure that the idx properly reflects the location of the new item
idx[onePair[0]] = g1;
}
// now do the same for the second item... but g1 will never be null, so
// this case is a little simpler.
if( !g2 ) {
g2 = g1;
g2.push( onePair[1] );
idx[onePair[1]] = g2;
}
if( g1 != g2 ) {
// now, if they're not already the same group, then merge the two
// groups, and update the idx to reflect the merge.
for( var z:int=0; z<g2.length; ++z ) {
idx[g2[z]] = g1;
g1.push( g2[z] );
g2.splice(0);
}
}
}
groups will end up being an array of arrays, just like you asked for -- but there will be a few empty arrays that can be discarded. Just prune (or ignore) the empty ones, and you'll have your groups.
the basic idea here, is that idx provides a lookup table that indicates, throughout the indexing process, for any given item, which group it's in (if any). This allows us to determine whether an item has been encountered previously or not, and if so, to utilize it's existing group.
You can use an Object to keep the track of the association of a pair iten and a group, the key will be each item of your pair.
Here a litle snippet that make the works :
var pairs:Array=[];
pairs[0] = ['ItemA', 'ItemB'];
pairs[1] = ['ItemA', 'ItemC'];
pairs[2] = ['ItemC', 'ItemD'];
pairs[3] = ['ItemC', 'ItemE'];
pairs[4] = ['ItemF', 'ItemG'];
pairs[5] = ['ItemF', 'ItemH'];
// will contain group created
var groups:Array=[];
// will contain association between a pair item and a group
var pair2group:Object={};
// function that turn pairs into groups
function makeGroups(pairs:Array):void{
var pairLen:int = pairs.length;
for (var i:int=0;i<pairLen;i++){
var pair:Array = pairs[i];
var item1:String = pair[0];
var item2:String = pair[1];
var group:Array = pair2group[item1];
// is first pair item already in a group
if (group == null) {
// no so create a new group
group=[];
// create the association
pair2group[item1] = group;
// add the item to the group we have created
group.push(item1);
// add it to all the groups
groups.push(group);
}
// is the second pair item into a grouo
if (pair2group[item2] == null) {
// no so add it to the group where the first item belong
group.push(item2);
// create the association for the second item
pair2group[item2] = group;
}
}
}
// ---- test
makeGroups(pairs);
trace(groups.length);
trace(groups[0]);
trace(groups[1]);
After lots of playing around here's the solution I came up with.
This will take an 2D overlapArray that has pairs and produce a group list with unique values.
I used a in_array() function to duplicate PHP's handy function for finding if an item is already in an array.
for each(var pair:Array in overlapArray) {
var pairInGroup = false;
for each(var group:Array in overlapArrayGroups) {
if(in_array(pair[0],group) || in_array(pair[1],group)) {
if(!in_array(pair[0],group)) {
group.push(pair[0]);
}
if(!in_array(pair[1],group)) {
group.push(pair[1]);
}
pairInGroup = true;
}
}
if(!pairInGroup) {
overlapArrayGroups.push(pair);
}
}
The in_array() function:
public static function in_array( needle:String, haystack:Array ):Boolean {
for( var a = 0; a < haystack.length; a++ ) {
if( haystack[a] == needle ) {
return true;
} else if( haystack[a] is Array ) {
return in_array(needle, haystack[a]);
}
}
return false;
}