Related
I have a collection of shifts for employees, data (trimmed out some details, but this is the structure for start/end times) looks like this:
{
"ref": Ref(Collection("shifts"), "123451234512345123"),
"ts": 1234567891012345,
"data": {
"id": 1,
"start": {
"time": 1659279600000
},
"end": {
"time": 1659283200000
},
"location": "12341234-abcd-1234-cdef-123412341234"
}
}
I have an index that will query return an array of shifts_by_location in this format: ["id", "startTime", "endTime"] ...
Now I want to create a user-defined-function to filter these results "start" and "end" times to fall in between given dayStart and dayEnd times to get shifts by date, hoping to get some FQL assistance here, thanks!
Here's my broken attempt:
Query(
Lambda(
["location_id", "dayStart", "dayEnd"], // example: ["124-abd-134", 165996000, 165922000]
Map(
Paginate(Match(Index("shifts_by_location"), Var("location_id"))),
Lambda(["id", "startTime", "endTime"],
If(
And(
GTE(Var("startTime"), Var("dayStart")), // GOAL -> shift starts after 8am on given day
LTE(Var("endTime"), Var("dayEnd")) // GOAL -> shift ends before 5pm on given day
),
Get(Var("shift")) // GOAL -> return shift for given day
)
)
)
)
)
Found a working solution with this query, the biggest fix was really just to use a filter over the map, which seems obvious in hindsight:
Query(
Lambda(
["location_id", "dayStart", "dayEnd"],
Filter(
Paginate(Match(Index("shifts_by_location"), Var("location_id"))),
Lambda(
["start", "end", "id"],
And(GTE(Var("start"), Var("dayStart")), LTE(Var("end"), Var("dayEnd")))
)
)
)
)
I am new to GAS with a little knowledge in Javascript
I am trying to read a list of IDs (column A in 'Outbound' sheet) and paste IDs to new 'temp' sheet (col A) and only show ID once if ID is duplicated, This part of my code is working fine.
Next I want to copy the rows of data over from 'Outbound' sheet to the new 'temp' sheet if ID match, but if a ID is duplicated then it will merge columns E:K.
I haven't got to the merging part as my code is not working when looking through the IDs and pasting the relevant rows across.
Link to Google Sheet and script: Click Here
This is my code so far, I appreciate some variables/lines of codes are not used as I have been playing around with my code and there may be ways to speed things up.
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getActiveSheet();
var newdata = new Array();
var data = ss.getDataRange().getValues(); // get all data
var destSheet = ss.getSheetByName("temp");
var lastRow = sheet.getLastRow();
var lastCol = sheet.getLastColumn();
function main(){
var data = findUnique();
sort();
copyRowData();
}
function findUnique(){
for(nn in data){
var duplicate = false;
for(j in newdata){
if(data[nn][col] == newdata[j][0]){
duplicate = true;
}
}
if(!duplicate){
newdata.push([data[nn][col]]);
}
}
//Logger.log(newdata);
}
function sort(){
newdata.sort(function(x,y){
var xp = Number(x[0]); // ensure you get numbers
var yp = Number(y[0]);
return xp == yp ? 0 : xp < yp ? -1 : 1; // sort on numeric ascending
});
//Logger.log(newdata);
destSheet.clear();
destSheet.getRange(1,1,newdata.length,newdata[0].length).setValues(newdata); // Paste unique HS ID to new tab
}
function copyRowData() {
//var sheet = ss.getSheetByName('Outbound'); //source sheet
var range = sheet.getRange(2,1,lastRow,5).getValues();
Logger.log(range);
var destlastRow = destSheet.getLastRow();
var criteria = destSheet.getRange(1,1,destlastRow).getValues();
Logger.log(criteria);
var data1 = [];
var j =[];
Logger.log(range.length);
//Condition to check in A:A, if true, copy the same row to data array
for (i=0;i<range.length;i++) {
for (j=0; j<criteria.length; j++){
if (range[i] == criteria[j]) {
data1.push(range[i]);
}
}
}
Logger.log(data1.length);
//Copy data array to destination sheet
destSheet.getRange(2,2,data1.length).setValues(data1);
//targetrange.setValues(data1)
}
I am looking for an output similar to this, where Shaun and Kennedy have merged data in cells E to K:
Click for image of expected outcome
Any help is much appreciated.
Modified Script
I approached this a bit differently from your script.
function main() {
let file = SpreadsheetApp.getActive();
let sourceSheet = file.getSheetByName("Outbound");
let sourceRange = sourceSheet.getDataRange();
let sourceValues = sourceRange.getValues();
// Removing header row into its own variable
let headers = sourceValues.shift();
//==========================================
// PHASE 1 - dealing with duplicates
// Initializing the duplicate checking object
// Using the ID as the key, objects will not
// allow duplicate keys.
let data = {}
// For each row in the source
// create another object with a key for each header
// for each key assign an array with the values
sourceValues.forEach(row => {
let rowId = row[0]
// If the id has already been added
if (rowId in data) {
// add the data to the array for each header
headers.forEach((header, index) => {
data[rowId][header].push(row[index]);
})
} else {
// create a new object with an array for each header
// initialize the array with one item
// the value of the cell
let entry = {}
headers.forEach((header, index) => {
entry[header] = [row[index]];
})
data[rowId] = entry
}
})
// PHASE 2 - creating the output
let output = []
// You don't want the name to be merged
// so put the indices of the columns that need to be merged here
let indicesToMerge = [4,5,6,7,9,10]
// For each unique id
for (let id in data) {
// create a row
let newRow = []
// temporary variable of id's content
let entry = data[id]
// for each header
headers.forEach((header, index) => {
// If this field should be merged
if (indicesToMerge.includes(index)) {
// joing all the values with a new line
let content = entry[header].join("\n")
// add to the new row
newRow.push(content)
} else {
// if should not be merged
// take the first value and add to new row
newRow.push(entry[header][0])
}
})
// add the newly constructed row to the output
output.push(newRow)
}
//==========================================
// update the target sheet with the output
let targetSheet = file.getSheetByName("temp");
let targetRange = targetSheet.getRange(
2,1,output.length, output[0].length
)
targetRange.setValues(output)
}
Which outputs this on the temp sheet:
How the script works
This script uses an object to store the data, here would be an example entry after the first phase of the script is done:
'87817':
{
ID: [87817, 87817, 87817],
Name: ["Kennedy", "Kennedy", "Kennedy"],
Surname: ["FFF", "FFF", "FFF"],
Shift: ["NIGHTS", "NIGHTS", "NIGHTS"],
"Area Manager completing initial conversation": ["AM1", "AM1", "AM1"],
"WC Date ": [
Sun Nov 29 2020 19:00:00 GMT-0500 (Eastern Standard Time),
Sun Feb 14 2021 19:00:00 GMT-0500 (Eastern Standard Time),
Sun Mar 07 2021 19:00:00 GMT-0500 (Eastern Standard Time),
],
"Score ": [0.833, 0.821, 0.835],
Comments: ["Comment 6", "Comment 10", "Comment 13"],
"Intial Conversation date": ["Continue to monitor - no action", "", ""],
"Stage 1 Meeting Date": [
"N/A",
Fri Feb 19 2021 19:00:00 GMT-0500 (Eastern Standard Time),
Mon Mar 29 2021 19:00:00 GMT-0400 (Eastern Daylight Time),
],
"Stage 1 Outcome": ["", "Go to Stage 1", "Stage 2"],
};
As you can see, if it finds a duplicate ID, for the first pass, it just copies all the information, including the name and surname etc.
The next phase involves going through each of these entries and merging the headers that need to be merged
by concatenating the results with a newline \n, resulting in a row like this:
[
87817,
"Kennedy",
"FFF",
"NIGHTS",
"AM1\nAM1\nAM1",
"Sun Nov 29 2020 19:00:00 GMT-0500 (Eastern Standard Time)\nSun Feb 14 2021 19:00:00 GMT-0500 (Eastern Standard Time)\nSun Mar 07 2021 19:00:00 GMT-0500 (Eastern Standard Time)",
"0.833\n0.821\n0.835",
"Comment 6\nComment 10\nComment 13",
"Continue to monitor - no action",
"N/A\nFri Feb 19 2021 19:00:00 GMT-0500 (Eastern Standard Time)\nMon Mar 29 2021 19:00:00 GMT-0400 (Eastern Daylight Time)",
"\nGo to Stage 1\nStage 2",
]
Comments
I believe the main difference between this script and yours is that it does everything in memory. That is, it gets all the data, and then never calls getRange or getValues again. Only at the end does it use getRange just for the purposes of outputting to the sheet.
The other difference appears to be that this one uses the inbuilt property of objects to identify duplicates. I.e. an object key cannot be duplicated inside an object.
Perhaps also, this approach takes two passes at the data, because the overhead is minimal and otherwise the code just gets hard to follow.
Merging data like this can get endless as there are many tweaks and checks that can be implemented, but this is a working bare-bones solution that can get you started.
I have a Ruby on Rails application to enter results and create a league table for a football competition.
I'm trying to input some results by creating records in the database through heroku and I get error messages.
The application isn't perfectly designed: to enter the results, I have to create the fixtures and enter the score for each team. Then, independently I have to record each goal scorer, creating a record for each goal which is either associated with an existing player or requires me to firstly create a new player and then create the goal.
When I ran the code below heroku, I got this error:
syntax error, unexpected ':', expecting keyword_end
Maybe I'm missing something simple about lopping through an array within a hash?
Thank you for any advice!
coalition = Team.find_by(name: "Coalition")
moscow_rebels = Team.find_by(name: "Moscow Rebels")
red_star = Team.find_by(name: "Red Star")
unsanctionables = Team.find_by(name: "The Unsanctionables")
cavalry = Team.find_by(name: "Cavalry")
galactics = Team.find_by(name: "The Galactics")
happy_sundays = Team.find_by(name: "Happy Sundays")
hardmen = Team.find_by(name: "Hardmen")
international = Team.find_by(name: "International")
evropa = Venue.find_by(name: "Evropa")
s28 = Season.find_by(number: 28)
start_time = DateTime.new(2020,9,6,11,0,0,'+03:00')
scheduled_matches_1 =
[
{team_1: cavalry, team_1_goals: 1, team_1_scorers: ["Minaev"], team_2_goals: 6, team_2_scorers: ["Kovalev", "Kovalev", "Kovalev", "Thomas", "Thomas", "Grivachev"], team_2: coalition, time: start_time, venue: evropa, season: s28},
{team_1: hardmen, team_1_goals: 4, team_1_scorers: ["Jones", "Jones", "Jones", "Fusi"], team_2_goals: 2, team_2_scorers: ["Kazamula", "Ario"], team_2: galactics, time: start_time + 1.hour, venue: evropa, season: s28},
{team_1: international, team_1_goals: 9, team_1_scorers: ["Kimonnen", "Kimonnen", "Kimonnen", "Burya", "Burya", "Zakharyaev", "Zakharyaev", "Lavruk", "Rihter"], team_2_goals: 0, team_2_scorers: [], team_2: happy_sundays, time: start_time+2.hours, venue: evropa, season: s28}
]
scheduled_matches.each do |match|
new_fixture = Fixture.create(time: match[:time], venue: match[:venue], season: match[:season])
tf1 = TeamFixture.create(team: match[:team_1], fixture: new_fixture)
tf2 = TeamFixture.create(team: match[:team_2], fixture: new_fixture)
ts1 = TeamScore.create(team_fixture: tf1, total_goals: match{:team_1_goals})
ts2 = TeamScore.create(team_fixture: tf2, total_goals: match{:team_2_goals})
match[:team_1_scorers].each do |scorer|
if Player.exists?(team: tf1.team, last_name: scorer)
Goal.create(team_score: ts1, player: Player.find_by(last_name: scorer))
else
new_player = Player.create(team: tf1.team, last_name: scorer)
Goal.create(team_score: ts1, player: new_player)
end
end
match[:team_2_scorers].each do |scorer_2|
if Player.exists?(team: tf2.team, last_name: scorer_2)
Goal.create(team_score: ts2, player: Player.find_by(last_name: scorer_2))
else
new_player = Player.create(team: tf2.team, last_name: scorer_2)
Goal.create(team_score: ts2, player: new_player)
end
end
end
It looks like you are using braces when you meant to use brackets to access the hash. Below is one of the issues, but the same issue is in ts2.
ts1 = TeamScore.create(team_fixture: tf1, total_goals: match{:team_1_goals})
should be match[:team_1_goals]
ts1 = TeamScore.create(team_fixture: tf1, total_goals: match[:team_1_goals])
It may be because you have scheduled_matches_1 at the top and scheduled_matches.each do... further down.
But the real issue here is that your variable names match the data content, rather than being used to hold the content. If a new team joins your league, you have to change the code. Next week, you are going to have to change the hard-coded date value. Your scheduled_matches_1 data structure includes the active record objects returned by the first set of Team.findByName() calls. It would be easier to fetch these objects from the database inside your loops, and just hold the team name as a string in the hash.
There is some duplication too. Consider that each fixture has a home team and an away team. Each team has a name, and an array (possibly empty) of the players who scored. We don't need the number of goals; we can just count the number of players in the 'scorers' array. The other attributes, like the location and season belong to the fixture, not the team. So your hash might be better as
{
"fixtures": [
{
"home": {
"name": "Cavalry",
"scorers": [
"Minaev"
]
},
"away": {
"name": "Coalition",
"scorers": [
"Kovalev",
"Kovalev",
"Kovalev",
"Thomas",
"Thomas",
"Grivachev"
]
},
"venue": "Evropa",
"season": "s28"
}
]
}
because then you can create a reusable method to process each team. And maybe create a new method that returns the player (which it either finds or creates) which can be called by the loop that adds the goals.
Also, as it stands, I'm not sure the code can handle 'own goals', either. Perhaps something for a future iteration :)
I'm trying to figure out how to extract records from a file that contains only one occurrence of a trainer and only one occurrence of a jockey.
Essentially, the record would imply that the jockey has only one ride for the day and it is for trainer X who has only one runner for the day.
Here are some "sample data":
ALLAN DENHAM,MUSWELLBROOK,RACE 5,MOPITTS (10),JEFF PENZA,B,5
ALLAN KEHOE,MUSWELLBROOK,RACE 3,FOXY FIVE (5),KOBY JENNINGS,C,3
ALLAN KEHOE,MUSWELLBROOK,RACE 4,BANGALLEY LAD (3),KOBY JENNINGS,BBB,4
ANDREW ROBINSON,MUSWELLBROOK,RACE 6,TROPHIES GALORE (4),DARRYL MCLELLAN,AAA,6
BEN HILL,MUSWELLBROOK,RACE 4,WHALER BILL (10),GRANT BUCKLEY,BB,4
BEN HILL,MUSWELLBROOK,RACE 5,MR BILL (5),GRANT BUCKLEY,BB,4
BJORN BAKER,MUSWELLBROOK,RACE 3,MISS JAY FOX (9),ALYSHA COLLETT,BB,3
BRETT CAVANOUGH,MUSWELLBROOK,RACE 3,OFFICE AFFAIR (10),RACHAEL MURRAY,B,3
BRETT THOMPSON,MUSWELLBROOK,RACE 7,COSTAS (2),RONALD SIMPSON,BB,7
CODY MORGAN,MUSWELLBROOK,RACE 6,BAJAN GOLD (5),JEFF PENZA,BB,6
CODY MORGAN,MUSWELLBROOK,RACE 7,RAPID EAGLE (9),DARRYL MCLELLAN,B,7
In the sample data, the first record that would meet my criteria would be the following:
BJORN BAKER,MUSWELLBROOK,RACE 3,MISS JAY FOX (9),ALYSHA COLLETT,BB,3
Note: BJORN BAKER only appears once and ALYSHA COLLETT only appears once.
In the sample data, trainer ALLAN DENHAM has only one runner for the day but jockey JEFF PENZA has 2 rides, one for trainer ALLAN DENHAM & one for trainer CODY MORGAN so this does not my meet my criteria.
Another record that would meet my criteria would be the following record:
BRETT CAVANOUGH,MUSWELLBROOK,RACE 3,OFFICE AFFAIR (10),RACHAEL MURRAY,B,3
Note: BRETT CAVANOUGH only appears once and RACHAEL MURRAY only appears once.
BRETT THOMPSON,MUSWELLBROOK,RACE 7,COSTAS (2),RONALD SIMPSON,BB,7
Note: BRETT THOMPSON only appears once and RONALD SIMPSON only appears once.
And so on...
I've loaded the "sample data" (top of page) into an array in Perl and have investigated how to use hash, etc. in order to extract the unique records but I cannot figure out how to extract the required records based on the uniqueness of the combination of the two elements (i.e. one trainer + the one corresponding jockey)
use Data::Dumper;
$infile = "TRAINER-JOCKEY-SAMPLE.txt";
open my $infile, "<:encoding(utf8)", $infile or die "$infile: $!";
my #recs = <$infile>;
close $infile;
my %uniques;
for my $rec (#recs)
{
my ($trainer, $racecourse, $racenum, $hnameandnum, $jockey, $TDRating, $rnum) = split(",", $rec);
++$uniques{$trainer}{$jockey};
}
print Dumper(\%uniques);
for my $trainer (sort keys %uniques)
{
my $answer = join ',', sort keys %{ $uniques{$trainer} };
print "$trainer has unique values $answer\n";
}
Note: I need to print the entire record when successful (see below):
BJORN BAKER,MUSWELLBROOK,RACE 3,MISS JAY FOX (9),ALYSHA COLLETT,BB,3
Your help would be greatly appreciated.
Both the trainer and the jockey have to appear just once in the list (unless the input has duplicate lines).
So, let's just count the occurrences of trainers. To be able to match them to jockeys, we'll store jockeys to trainers in a hash of hashes.
Once we build the two structures, just select the jockeys with only one associated trainer and check that the trainer appeared just once, which had to be with the jockey they were associated to.
#!/usr/bin/perl
use warnings;
use strict;
use feature qw{ say };
my (%jockeys, %trainers);
while (<>) {
my ($jockey, $trainer) = (split /,/)[0, 4];
++$trainers{$trainer};
undef $jockeys{$jockey}{$trainer};
}
for my $jockey (keys %jockeys) {
next if 1 < keys %{ $jockeys{$jockey} };
my $trainer = (keys %{ $jockeys{$jockey} })[0];
say "$jockey,$trainer" if 1 == $trainers{$trainer};
}
Update: To print the whole lines, we need to store them somewhere, too. We can slightly modify the program by remembering the whole lines in another hash; we can use either the trainer or the jockey as the key.
#!/usr/bin/perl
use warnings;
use strict;
my (%jockeys, %trainers, %full);
while (<>) {
my ($jockey, $trainer) = (split /,/)[0, 4];
++$trainers{$trainer};
undef $jockeys{$jockey}{$trainer};
$full{$jockey} = $_;
}
for my $jockey (keys %jockeys) {
next if 1 < keys %{ $jockeys{$jockey} };
my $trainer = (keys %{ $jockeys{$jockey} })[0];
print $full{$jockey} if 1 == $trainers{$trainer};
}
have a nice day everyone, i want to ask something, i need to make JSON array using square bracket instead of curly breacket, but now i've JSON like this:
{
noTransaksi: "202006041323372",
nopolTransaksi: "B11",
nominalTransaksi: "1.000",
masukTransaksi: "04 June 2020 13:23:37",
keluarTransaksi: "04 June 2020 14:26:25",
lokasiTransaksi: "Jakarta",
nipKaryawan: "002002",
shiftTransaksi: "1"
},
{
noTransaksi: "202006040703302",
nopolTransaksi: "B2213",
nominalTransaksi: "0",
masukTransaksi: "04 June 2020 07:03:30",
keluarTransaksi: "04 June 2020 14:25:42",
lokasiTransaksi: "Jakarta",
nipKaryawan: "002007",
shiftTransaksi: "1"
},//...
i want to change it to something like this:
[
noTransaksi: "202006041323372",
nopolTransaksi: "3752",
nominalTransaksi: "1.000",
masukTransaksi: "04 June 2020 13:23:37",
keluarTransaksi: "04 June 2020 14:26:25",
lokasiTransaksi: "RSUDTA",
nipKaryawan: "002002",
shiftTransaksi: "1"
],
[
noTransaksi: "202006040703302",
nopolTransaksi: "AG1592",
nominalTransaksi: "0",
masukTransaksi: "04 June 2020 07:03:30",
keluarTransaksi: "04 June 2020 14:25:42",
lokasiTransaksi: "RSUDTA",
nipKaryawan: "002007",
shiftTransaksi: "1"
],//....
so i can fit the JSON to my datatable, because it need square bracket instead of curly bracket, anyway i'm using reactjs too, it is possible to make JSON array like that?
oh ya, this is my code
if(mysqli_num_rows($result) > 0){
$emparray = array();
if(mysqli_num_rows($result) > 0){
while ($row = mysqli_fetch_assoc($result)) {
$emparray[] = array(
'noTransaksi'=>$row['noTransaksi'],
'nopolTransaksi'=>strtoupper($row['nopolTransaksi']),
'nominalTransaksi'=>number_format($row['nominalTransaksi'],0,",","."),
'masukTransaksi'=>date("d F Y H:i:s", strtotime($row['masukTransaksi'])),
'keluarTransaksi'=>date("d F Y H:i:s", strtotime($row['keluarTransaksi'])),
'lokasiTransaksi'=>strtoupper($row['lokasiTransaksi']),
'nipKaryawan'=>strtoupper($row['nipKaryawan']),
'shiftTransaksi'=>$row['shiftTransaksi'],
);
}
$no++;
}
echo json_encode($emparray);
}
mysqli_close($con);
i really appriciate if somebody can help me:)
The square brackets produce a list/array.
The curly brackets produce an object with key/value pairs.
The list can then be a value of a key/value pair.
you cant just change it u can use [] inside the {} brackets