Solving: How many shops are open at a certain time? - algorithm

I was posed this question at an interview and never really came up with a great solution. Does anyone have an "optimum" solution? Where the target is efficiency and being able to deal with large input.
Material Provided:
I am given a long list of shops and their opening/closing times (say 1000).
The Problem:
For a given time of day, return how many of the shops are open
Example Data:
Sainsburys 10:00 23:00
Asda 02:00 18:00
Walmart 17:00 22:00
Example In/Out
Input | Output
12:00 | 2
22:00 | 1 (walmart shut # 22:00)
17:30 | 3
The two parts of the problem are how to store the data and how to efficiently get the answer, I guess how you're reading the input etc doesn't really matter.
Thanks for your time and insight!

Let's take a stab:
//First, we turn the time input into an int and then compare it to the open and
//closing time ints to determine if the shop is open. We'l use 10:00 in this example.
//get magic time int
int magicTimeInt = CInt("10:00".Replace(":",""));
int openstorecount = 0;
foreach(var shoptime in ShopTimesList)//SHopTImesList is the list of shop names and times
{
string[] theShop = shoptime.Split(" ");
if( CInt(theshop[1].ToString().Replace(":", "")) < magicTimeInt
&&
CInt(theshop[2].ToString().Replace(":", "")) > magicTimeInt)
{
openstorecount++;
}
}
Console.WriteLine("10:00 | " + openstorecount.ToString());

I would use a database:
TABLE shops (
name VARCHAR,
open TIME,
close TIME
)
SELECT count(*) AS number_of_shops FROM shops WHERE [input_time] BETWEEN open AND close
To prevent the query from counting walmart (in your example), you could add a second to open and substract a second from close (or some minutes to give anyone the chance to buy something).

I would do it Java:
class Shop {
String name;
Time opening, closing;
Shop(String name; Time opening, Time closing){
this.name = name;
this.opening = opening;
this.closing = closing;
}
public boolean isOpen(Time time){
return opening.before(time) && closing.after(time)
}
}
Add code to trim date information from the time values, and just make a collection of all the stores, iterate through, and incerment your count for each open one.

Related

I need to find a faster solution to iterate rows in Google App Script

I'm trying to save some rows values for multiple columns on multiple tabs in GAS, but it's taking a lot of time and I'd like to find a faster way of doing this, if there's any.
A project e.g:'Project1' -as a key- has a value associated with it which corresponds to the column where it's stored, the tabs are 600+ iterations long.
this script opens up a tab called 'person1' at first and goes through all the rows for the column that corresponds to that project in 'projects' dictionary (it's the same format for every tab, but more projects will be added in the future)
right now i'm iterating through the 'members' dictionary (length=m), then through the projects dictionary (length=p) and finally through the length of the rows (length='r'), in the meantime it access the other spreadsheet where I want to save all those rows.
This means that the current time complexity of my algorithm is O(mpr) and it's WAY too slow.
for 15 people and 6 projects each, the amount of iterations would be 156600+ = 54,000 iterations at least (more people and more projects and more rows will be added).
is there any way to make my algorithm faster?
const members = {'Person1':'P1', 'Person2':'P2'};
const projects = {'Project1':'L','Project2':'R'}
function saveRowValue() {
let sourceSpreadsheet = SpreadsheetApp.getActiveSpreadsheet();
let targetSpreadsheet = SpreadsheetApp.openById('-SPREADSHEET-');
let targetSheet = targetSpreadsheet.getSheetByName('Tracking time');
let rowsToWrite = [];
rowsToWrite.push(['Project', 'Initials', 'Date', 'Tracking time'])
var rowsToSave = 1;
for(m in members){
Logger.log(m +' initials:'+ members[m]);
let sourceSheet = sourceSpreadsheet.getSheetByName(m);
for(p in projects){
let values = sourceSheet.getRange(projects[p]+"1:"+projects[p]).getValues();
Logger.log(values)
let list = [null, 0,''];
for(var i=0; i<values.length; i++){
try{
date = sourceSheet.getRange('B'+i).getValue();
let val = sourceSheet.getRange(projects[p]+i)
val = Utilities.formatDate(val.getValue(), "GMT", val.getNumberFormat())
Logger.log(val);
if(!(list.includes(val)) && date instanceof Date){
//rowsToWrite.push();
rowsToSave++;
targetSheet.getRange(rowsToSave,1,1,4).setValues([[p, members[m], date, val]]);
}
}catch(e){
Logger.log(e)
}
}
}
}
Logger.log(rowsToWrite);
[Here you can see how much time it takes to iterate 600 rows for a single project and a single member after changing what Yuri Khristich told me to change][1]
[1]: https://i.stack.imgur.com/CnRZY.png
First step is to try to get rid of getValue() and setValue() in loops. All data should be captured at once as 2D arrays in one step and put on the sheet in one step as well. No single cell or single row operations.
Next trick depends on your workflow. Say, it's unlikely that every time all 54000+ cells need to be checked. Probably there are ranges that have no changes. You can figure out some way to indicate the changes. And process only the changed ranges. Probably, the indication could be performed with onChange() trigger. For example you can add * to the name of the sheets and columns where changes have occurred and remove these * whenever you run your script.
Reference:
Use batch operations

SSIS Data Flow: Aggregate Task 'hides' my other columns downstream

I'm hoping someone can help me with this.
I have an SSIS package that updates a table, and one of it's columns is a 'current average'. In my Data Flow Task, I need to look at 'tickets sold' for each record, aggregate the average, and add it as part of my insert.
Problem is, that Aggregate Task hides all my other columns. I've got 'tickets' and 'avg tickets', 'venue' and 'time'. When I go to put in the record to my DB Destination, all 3 source columns (venue, time, tickets) aren't visible, and the only one available is my aggregate. I need all four for my insert. How do I get those other columns to 'pass through' the aggregate task so I can use them?
Source: Excel sheet
Venue, Tickets Sold, Show Time
Royal Oak Music Theatre, 300, 7:00 PM
Saint Andrew's Hall, 200, 9:00 PM
Fox Music Theatre, 700, 8:00 PM
Destination: SQL Table
Venue, Tickets Sold, Show Time, Average Tickets Sold Per Show
Royal Oak Music Theatre, 300, 7:00PM, 300
Saint Andrews Halls, 200, 9:00PM, 250
Fox Music Theatre, 700, 8:00PM, 400
Given your sample data, it appears you're creating a running average. Each row in adds a new weight to be factored into the average.
The challenge is, the Aggregate component in SSIS doesn't do that. It's going to give you an average by each grouping (or none, in your case).
You're going to need a Script Component to compute this.
Check the "Tickets Sold" column as an input for the script (which will likely be named TicketsSold or Tickets_Sold or some permutation there of)
You'll need to define a new column in your Output Buffer I'll assume is named runningAverage and it's type is dt_numeric,
I'm free handing this code so syntax errors are mine but the logic is sound ;)
public class ScriptMain : SomeComponent
{
int itemCount;
int total;
/// initialize members
public override void PreExecute()
{
this.itemCount = 0;
this.total = 0;
}
/// Process all the rows, one at a time
public override void Input0_ProcessInputRow(Input0Buffer Row)
{
// accumulate
this.itemCount++;
this.total += Row.TicketsSold;
// populate the new column
// force the floating point division lest we truncate with integer division
Row.runningAverage = this.total / (this.itemCount * 1.0);
}
}

Script to create same Google Classroom assignment for each day of the school year

Does anyone know of a script that I could adapt to create the same assignment for each school day of a given school year? For example, I would like to create the assignment "Practice your Anki deck. Submit screenshot of your stats" every school day in our class BasicSkills. Ideally, the assignment would be scheduled the week before it was due. This would be a great time saver for those of us elementary school teachers using Google Classroom who have lots of daily and weekly repeating tasks.
I was a programmer many years ago and could adapt an existing script but would struggle to get this working just based on the API description. Thanks.
I think you can, it just depends on how you'll approach it. I'll give you a skeletal structure of the code:
function myFunction() {
Date.prototype.addDays = function(days) {
var dat = new Date(this.valueOf());
dat.setDate(dat.getDate() + days);
return dat;
}
var i;
for (i = 0; i < 3; i++){
var dat = new Date();
Logger.log(dat.addDays(i))
var ClassSource = {
title: "Test File" + dat.addDays(i),
state: "DRAFT",
workType: "ASSIGNMENT"
};
Classroom.Courses.CourseWork.create(ClassSource, 4965804775)
}
//Logger.log(exec);
}
How to approach your goal:
Ideally you want to create the assignment in one go but I don't recommend since there are limitations that you'll encounter (e.g. timeout).
Next, if ever you'll decide to do it in one go, I recommend you to use Utilities.sleep(1000) between calls.
You can also create a list of dates that don't have a class like saturday, sunday, holiday.
Sample result:
Hope this helps.

Timezone Manipulation

I'm working on a project (online game) where users have the ability to use a coded 'airport' to travel to different countries & cities. Once they have travelled, the cityid within the database will update for example:
cityid = 1 (England - London)
cityid = 2 (USA - LA)
Therefore if a user travels from England to the USA it will store database side cityid = 2.
Now,
Whilst this is functional, I wish to incorporate timezone changes into it (if at all possible) I have tried:
if ($user->cityid == 3)
{
$timestamp ='1502448414'; //Timestamp which you need to convert
$dt = new \DateTime("#$timestamp");
$destinationTimezone = new \DateTimeZone('Mexico/General'); // To which timezone you need to convert
$dt->setTimeZone($destinationTimezone); // Set timezone
echo 'Mexico: '. $dt->format('H:i a'), "\n"; // Echo your changed datetime
}
As you can see, I have used Mexico as a demo to try and figure out my approach.
However, this only fetches the timestamped time rather than the realtime. Im aware, I could simply add the timestamp into a database table and then run a cron every second to update the table but this seems rather a long winded route.
Now within app.php the standard setting is UTC which runs as a realtime clock by returning: date('H:i:s').
My question is (after a lot of google searching) is there a way to manipulate this to make date() output the new time of (USA) when it has been travelled to?
Apologies that I cannot add anymore coding into this question, I have no real idea of how to approach it other than the one stated above.
Using Carbon
if ($user->cityid == 3) {
$dt = \Carbon\Carbon::now("Your current location timezone");
$dt->setTimeZone('Mexico/General');
echo 'Mexico: '. $dt->format('H:i a'), "\n";
}

very basic pig-latin beginner code

I am new to hadoop and all its derivatives. And I am really getting intimidated by the abundance of information available.
But one thing I have realized is that to start implementing/using hadoop or distributed codes, one has to basically change the way they think about a problem.
I was wondering if someone can help me in the following.
So, basically (like anyone else) I have a raw data.. I want to parse it and extract some information and then run some algorithm and save the results.
Lets say I have a text file "foo.txt" where data is like:
id,$value,garbage_field,time_string\n
1, 200, grrrr,2012:12:2:13:00:00
2, 12.22,jlfa,2012:12:4:15:00:00
1, 2, ajf, 2012:12:22:13:56:00
As you can see that the id can be repeated.This id can be like how much money a customer has spent!!
What I want to do is save the result in a file which contains how much money each of the customer has spent in "morning","afternoon""evening""night"
(You can define your some time buckets to define what morning and all is.
For example here probably
1, 0,202,0,0
1 is the id, 0--> 0$ spent in morning, 202 in afternon, 0 in evening and night
Now I have a python code for it.. But I have to implement this in pig.. to get started.
If anyone can just write/guide me thru this.. Thats all I need to get started.
Thanks
I'd start like this:
foo = LOAD 'foo.txt' USING PigStorage(',') AS (
CUSTOMER_ID:int,
DOLLARS_SPENT:float,
GARBAGE_FIELD,
TIME_STRING:chararray
);
foo_with_timeslots = FOREACH foo {
GENERATE
CUSTOMER_ID,
DOLLARS_SPENT,
/* DO TIME SLOT CALCULATION HERE */ AS TIME_SLOT
;
}
I don't have much knowledge of date/time values in pig, so I'll leave how to do conversion from time string to timeslot, to you.
id_grouped_foo_with_timeslots = GROUP foo_with_timeslots BY (
CUSTOMER_ID,
TIME_SLOT
);
-- Calculate how much each customer spent at time slots
spent_per_customer_per_timeslot = FOREACH id_grouped_foo_with_timeslots {
GENERATE
group.CUSTOMER_ID as CUSTOMER_ID,
group.TIME_SLOT as TIME_SLOT,
SUM(foo_with_timeslots.DOLLARS_SPENT) as TOTAL_SPENT
;
}
You'll have an output like below in spent_per_customer_per_timeslot
1,Morning,200
1,Evening,100
2,Afternoon,30
At this point it should be trivial to re-group the data and put it in the shape you want.

Resources