Remove Element from the linked list - linked-list

def removeKFromList(l, k):
pointer = l
while pointer:
if pointer.next and pointer.next.value == k:
pointer.next = pointer.next.next
else:
pointer = pointer.next
if l and l.value == k:
return l.next
else:
return l
In this code, why do I need to put
pointer = pointer.next
under else? Code does not work if I don't write this under else, but I don't see why.

First realise that pointer is intended to reference the node that precedes the one that might need to be deleted.
Now if we find that the successor of pointer must be deleted, then we get in the if block. In that case the removal of the next node will make the node that comes after that one, the new successor of pointer. As we want to make the check (for deletion) also for that new successor, we should not move pointer, but just leave it like that. In the next iteration we will then correctly determine whether that new successor node must be deleted or not.
If we would have moved pointer with pointer.next, then pointer would refer to the new successor, but it would not be checked for removal (in the next iteration). It would escape the removal check!
Here is a visualisation of what can go wrong when we do pointer = pointer.next in that case.
Input: l = [1,2,2,3], k = 2
l
pointer
↓
┌───────────┐ ┌───────────┐ ┌───────────┐ ┌───────────┐
│ value: 1 │ │ value: 2 │ │ value: 2 │ │ value: 3 │
│ next: ───────> │ next: ───────> │ next: ───────> │ next:None │
└───────────┘ └───────────┘ └───────────┘ └───────────┘
In the first iteration the condition pointer.next.value == k is true, and so the removal is performed with pointer.next = pointer.next.next, resulting in this situation:
l
pointer
↓ ┌────────────────┐
┌───────────┐ │ ┌───────────┐ │ ┌───────────┐ ┌───────────┐
│ value: 1 │ │ │ value: 2 │ └> │ value: 2 │ │ value: 3 │
│ next: ──────┘ │ next: ───────> │ next: ───────> │ next:None │
└───────────┘ └───────────┘ └───────────┘ └───────────┘
If now we would do pointer = pointer.next, then we get this:
l pointer
↓ ┌────────────────┐ ↓
┌───────────┐ │ ┌───────────┐ │ ┌───────────┐ ┌───────────┐
│ value: 1 │ │ │ value: 2 │ └> │ value: 2 │ │ value: 3 │
│ next: ──────┘ │ next: ───────> │ next: ───────> │ next:None │
└───────────┘ └───────────┘ └───────────┘ └───────────┘
...and in the next iteration the if condition will not be about that node, but about the next, the one with value 3, and so the second occurrence of 2 will not be deleted!

Related

asof join with Julia data tools

I am hoping to do something along the lines of pandas merge_asof or QuestDB's ASOF JOIN in Julia. Critically, I also need to apply a group-by operation.
I would be happy to use any of Julia's Table.jl respecting tools. DataFrame's leftjoin get's close, but requires exact key matches, and doesn't do grouping (as far as I can tell). SplitApplyCombine.jl's leftgroupjoin allows you to pass in your own comparison function, but I don't quite see how to use that function to specify the "nearest less than" value, or "nearest greater than" value.
For a simple example where group-bys are not necessary, on two tables left and right, each with a column time, I could use a function like
function find_nearest_before(val, data)
findlast(x -> x <= val, data)
end
[find_nearest_before(t, right.time) for t in left.time]
and this would get me the indices in right to join to left. However, I don't quite see how to put this together with a group-by.
EDIT
Adding an example to make the question more clear. The first table sensor_pings reports when a sensor sees something. The second table in_sensor_FOV tells us what object is actually in a sensor's field of view (FOV) at a given time. Assume a sensor only has one object in its FOV at a time (opposite is not necessarily true).
julia> using TypedTables
julia> sensor_pings = Table(time=[4,5,7,8,9,10,11,13,15,16], sensor_id=[2,1,1,3,2,3,1,2,3,2])
Table with 2 columns and 10 rows:
time sensor_id
┌────────────────
1 │ 4 2
2 │ 5 1
3 │ 7 1
4 │ 8 3
5 │ 9 2
6 │ 10 3
7 │ 11 1
8 │ 13 2
9 │ 15 3
10 │ 16 2
julia> in_sensor_FOV = Table(time=[1.3,2.6,3.8,5.9,7.3,8.0,12.3,14.7], sensor_id=[3,1,2,3,2,2,3,1], object_in_sensor_FOV=[:a,:b,:c,:b,:c,:a,:c,:b])
Table with 3 columns and 8 rows:
time sensor_id object_in_sensor_FOV
┌──────────────────────────────────────
1 │ 1.3 3 a
2 │ 2.6 1 b
3 │ 3.8 2 c
4 │ 5.9 3 b
5 │ 7.3 2 c
6 │ 8.0 2 a
7 │ 12.3 3 c
8 │ 14.7 1 b
The end result of the desired operation would look like
julia> Table(time=[4,5,7,8,9,10,11,13,15,16], sensor_id=[2,1,1,3,2,3,1,2,3,2], object_in_sensor_FOV=[:c,:b,:b,:b,:a,:b,:b,:a,:c,:a])
Table with 3 columns and 10 rows:
time sensor_id object_in_sensor_FOV
┌──────────────────────────────────────
1 │ 4 2 c
2 │ 5 1 b
3 │ 7 1 b
4 │ 8 3 b
5 │ 9 2 a
6 │ 10 3 b
7 │ 11 1 b
8 │ 13 2 a
9 │ 15 3 c
10 │ 16 2 a
It's rather easy to write something like that, you just need to implement double cursor
using TypedTables
using Setfield
sensor_pings = Table(time=[4,5,7,8,9,10,11,13,15,16], sensor_id=[2,1,1,3,2,3,1,2,3,2])
in_sensor_FOV = Table(time=[1.3,2.6,3.8,5.9,7.3,8.0,12.3,14.7], sensor_id=[3,1,2,3,2,2,3,1], object_in_sensor_FOV=[:a,:b,:c,:b,:c,:a,:c,:b])
function mergeasof(t1, t2)
objects = similar(t2.object_in_sensor_FOV, length(t1.time))
d = ntuple(_ -> :z, 3) # :z is a sentinel value, means that there were no objects up to this moment. Can be anything
i2 = 1
# Double cursor
for i1 in axes(t1, 1)
tm1 = t1.time[i1]
# updating `d` to the current time step
while i2 <= length(t2.time)
t2.time[i2] > tm1 && break
#set! d[t2.sensor_id[i2]] = t2.object_in_sensor_FOV[i2]
i2 += 1
end
objects[i1] = d[t1.sensor_id[i1]]
end
return Table(time = t1.time, sensor_id = t1.sensor_id, object_in_sensor_FOV = objects)
end
julia> mergeasof(sensor_pings, in_sensor_FOV)
Table with 3 columns and 10 rows:
time sensor_id object_in_sensor_FOV
┌──────────────────────────────────────
1 │ 4 2 c
2 │ 5 1 b
3 │ 7 1 b
4 │ 8 3 b
5 │ 9 2 a
6 │ 10 3 b
7 │ 11 1 b
8 │ 13 2 a
9 │ 15 3 c
10 │ 16 2 a
it should be rather fast and could be adapted for an arbitrary number of columns (it's just more tedious to right).
Few notes, though
This function expects that tables are sorted over time
It can be adapted to forward search, yet it can be more tedious.
I am using the fact that there are 3 sensors. If the amount of sensors is known beforehand, then it can should be used in ntuple function. If it is unknown or large or indices are arbitrary, then instead of ntuple you can use Dict
d = Dict{Int, Symbol}()
and #set! should be removed
d[t2.sensor_id[i2]] = t2.object_in_sensor_FOV[i2]
and instead of
objects[i1] = d[t1.sensor_id[i1]]
you should use
objects[i1] = get(d, t1.sensor_id[i1], :z)
Here's one way of doing it in DataFrames - this is certainly not the peak of efficiency, but if your data is small enough that you can afford the first leftjoin it might be good enough.
Start by joining in_sensor_FOV onto sensor_pings:
julia> df = leftjoin(sensor_pings, in_sensor_FOV, on = :sensor_id, makeunique = true);
after that you'll have multiple rows for each sensor in sensor_pings, which is where this approach might fail if your data is large.
Then get the time difference:
julia> transform!(df, [:time, :time_1] => ((x, y) -> x - y) => :time_diff);
Now your findlast approach iiuc means we only consider rows with positive time difference:
julia> df = df[df.time_diff .> 0.0, :];
Then we sort by sensor and time diff and pick the first row for each sensor:
julia> res = combine(groupby(sort(df, [:sensor_id, :time_diff]), [:sensor_id, :time]), names(df[:, Not([:sensor_id, :time])]) .=> first .=> names(df[:, Not([:sensor_id, :time])]));
Result (sorted to produce the same output):
julia> sort(select(res, [:time, :sensor_id, :object_in_sensor_FOV]), :time)
10×3 DataFrame
Row │ time sensor_id object_in_sensor_FOV
│ Int64 Int64 Symbol
─────┼────────────────────────────────────────
1 │ 4 2 c
2 │ 5 1 b
3 │ 7 1 b
4 │ 8 3 b
5 │ 9 2 a
6 │ 10 3 b
7 │ 11 1 b
8 │ 13 2 a
9 │ 15 3 c
10 │ 16 2 a

How to improve ILIKE Performance?

My application has a page where all the cities of a state that start with a particular alphabet are shown.
For ex:
State: Alabama, Page A
--> All cities in Alabama starting with alphabet 'A'
This is my query
City.where(state: 'Alabama').where("name ilike?", "a%")
This query takes ~110 - 140 ms. Is there any way in which I can bring down the query time to <10 ms.
Thanks in advance :)
PostgreSQL doesn't use usual index for LIKE operator
postgres=# create index on obce(nazev);
CREATE INDEX
Time: 120.605 ms
postgres=# explain analyze select * from obce where nazev like 'P%';
┌─────────────────────────────────────────────────────────────────────────────────────────────────────┐
│ QUERY PLAN │
╞═════════════════════════════════════════════════════════════════════════════════════════════════════╡
│ Seq Scan on obce (cost=0.00..137.12 rows=435 width=41) (actual time=0.023..2.345 rows=450 loops=1) │
│ Filter: ((nazev)::text ~~ 'P%'::text) │
│ Rows Removed by Filter: 5800 │
│ Planning time: 0.485 ms │
│ Execution time: 2.413 ms │
└─────────────────────────────────────────────────────────────────────────────────────────────────────┘
(5 rows)
You should to use special syntax with varchar_pattern_ops keyword
postgres=# create index on obce(nazev varchar_pattern_ops);
CREATE INDEX
Time: 124.709 ms
postgres=# explain analyze select * from obce where nazev like 'P%';
┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
│ QUERY PLAN │
╞═════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════╡
│ Bitmap Heap Scan on obce (cost=12.39..76.39 rows=435 width=41) (actual time=0.291..0.714 rows=450 loops=1) │
│ Filter: ((nazev)::text ~~ 'P%'::text) │
│ Heap Blocks: exact=58 │
│ -> Bitmap Index Scan on obce_nazev_idx1 (cost=0.00..12.28 rows=400 width=0) (actual time=0.253..0.253 rows=450 loops=1) │
│ Index Cond: (((nazev)::text ~>=~ 'P'::text) AND ((nazev)::text ~<~ 'Q'::text)) │
│ Planning time: 0.953 ms │
│ Execution time: 0.831 ms │
└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
(7 rows)
But this doesn't work for ILIKE - the workaround can be functional index:
create index on obce(upper(nazev) varchar_pattern_ops);
select * from obce where upper(nazev) like upper('P%');
Note: "Nazev" is the name in Czech language
Another possibility is using pg_trgm extension and using trigram index. It is working for both LIKE, ILIKE, but the index is much bigger - it is not problem for relative small static tables.
create extension pg_trgm ;
create index on obce using gin (nazev gin_trgm_ops);
postgres=# explain analyze select * from obce where nazev like 'P%';
┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
│ QUERY PLAN │
╞═════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════╡
│ Bitmap Heap Scan on obce (cost=15.37..79.81 rows=435 width=41) (actual time=0.327..0.933 rows=450 loops=1) │
│ Recheck Cond: ((nazev)::text ~~ 'P%'::text) │
│ Rows Removed by Index Recheck: 134 │
│ Heap Blocks: exact=58 │
│ -> Bitmap Index Scan on obce_nazev_idx1 (cost=0.00..15.26 rows=435 width=0) (actual time=0.287..0.287 rows=584 loops=1) │
│ Index Cond: ((nazev)::text ~~ 'P%'::text) │
│ Planning time: 0.359 ms │
│ Execution time: 1.056 ms │
└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
(8 rows)

Rails + PostgreSQL: grouping together with a sum

I have a table with this structure:
id | name | batch_id | used
----------------------------------
1 | voucher 1 | 1 | 1
2 | voucher 2 | 1 | 0
3 | voucher 3 | 1 | 1
4 | voucher 4 | 2 | 0
5 | voucher 5 | 3 | 1
And I need to run a query that will group by batch_id and do a sum on the used column.
So the outcome that I need is:
batch_id | sum_used
----------------------------------
1 | 2
2 | 0
3 | 1
This is what I have so far:
TableName.select('DISTINCT ON (batch_id) batch_id')
Which is the same as:
SELECT DISTINCT ON (batch_id) batch_id FROM table_name
Grouping works but I can't get the sum to work.
Can anyone point me in the right direction?
You need to use GROUP BY and SUM aggregation function:
SELECT batch_id, SUM(used::int) AS sum_used
FROM table_name
GROUP BY batch_id
ORDER BY batch_id;
SqlFiddleDemo
Output:
╔═══════════╦══════════╗
║ batch_id ║ sum_used ║
╠═══════════╬══════════╣
║ 1 ║ 2 ║
║ 2 ║ 0 ║
║ 3 ║ 1 ║
╚═══════════╩══════════╝
Alternatively using windowed function:
SELECT DISTINCT batch_id, SUM(used::int) OVER(PARTITION BY batch_id) AS sum_used
FROM table_name
ORDER BY batch_id
SqlFiddleDemo2
Hey you can try this way:
TableName.select('batch_id as batch_id , sum(used) as sum_used').group(:batch_id)

Autolayout table cell with image and text fields?

I'm looking to do a table view cell with a photo and wrapping text with auto layout. I've managed a lot with auto layout, but I'm at a loss on how to do this one.
┌─────────────────────────────────────────────────────┐
│ ┌──────────┐ ┌────────────────────────────────────┐ │
│ │ │ │ Title (might wrap) │ │
│ │ │ └────────────────────────────────────┘ │
│ │ Photo │ ┌────────────────────────────────────┐ │
│ │ │ │ Body text. May wrap, may contain │ │
│ │ │ │ multiple lines. │ │
│ │ │ └────────────────────────────────────┘ │
│ └──────────┘ │
└─────────────────────────────────────────────────────┘
As the text expands, I want to keep the photo in the top left and expand the cell. However, the cell should never shrink below the minimum required to show the photo (with margins).
┌─────────────────────────────────────────────────────┐
│ ┌──────────┐ ┌────────────────────────────────────┐ │
│ │ │ │ Title (might wrap) │ │
│ │ │ │ Maybe even to two lines. │ │
│ │ Photo │ └────────────────────────────────────┘ │
│ │ │ ┌────────────────────────────────────┐ │
│ │ │ │ Body text. May wrap, may contain │ │
│ │ │ │ multiple lines. │ │
│ └──────────┘ │ │ │
│ │ Text could require more vertical │ │
│ │ space than the photo. │ │
│ └────────────────────────────────────┘ │
└─────────────────────────────────────────────────────┘
I'm requiring iOS 8 or later.
I've tried doing this with just the three views listed, and also by putting the left item and right items in two views. Every combination I try seems to ignore the photo's minimum size.
(Btw, for anyone curious: Graphic via Monodraw.)
Try having the following relationships:
Photo:
width = X
height = Y
left = Cell + Z
top = Cell + Z
Title:
left = Photo + Z
right = Cell - Z
top = Cell + Z
the label will auto calculate the height based on content
Body:
Left = Title
Right = Title
Top = Title.Bottom + Z
Cell: (this is the important part)
Bottom >= (equal to or greater than) Body.Bottom + Z
Bottom >= Photo.Bottom + Z
this will force the cell to be, at all times, either taller than the image + offset or taller than the label + offset

Ordering records by number of occurrences in the database

In Rails 4.0 I have this table and I want to sort it by the number of occurrences of location_id. In this case the most popular location_id is 3. I want to sort my table in descending order starting with all records with location_id: 3 on the top.
Table Geochecks-
┌────┬─────────┬─────────────┬─────────────────────┬────────────────────┬─────────────────────┐
│ id │ user_id │ location_id │ message │ created_at │ updated_at │
├────┼─────────┼─────────────┼─────────────────────┼────────────────────┼─────────────────────┤
│ 1 ╎ 14 ╎ 2 ╎ Test test t ╎ 2013-07-23 13:3... ╎ 2013-07-23 13:37... │
│ 2 ╎ 12 ╎ 3 ╎ ╎ 2013-07-23 13:5... ╎ 2013-07-23 13:54... │
│ 3 ╎ 15 ╎ 2 ╎ <html lang="en" ... ╎ 2013-07-25 08:5... ╎ 2013-07-25 08:57... │
│ 4 ╎ 12 ╎ 3 ╎ Ohohohooh ╎ 2013-07-25 11:3... ╎ 2013-07-25 11:37... │
│ 5 ╎ 12 ╎ 3 ╎ Pff kjasakljdfas... ╎ 2013-07-25 11:3... ╎ 2013-07-25 11:37... │
│ 6 ╎ 15 ╎ 4 ╎ ╎ 2013-07-25 13:5... ╎ 2013-07-25 13:54... │
│ 7 ╎ 13 ╎ 4 ╎ dasfdasfdasfdasf ╎ 2013-07-25 14:3... ╎ 2013-07-25 14:30... │
│ 8 ╎ 13 ╎ 3 ╎ ╎ 2013-07-25 14:3... ╎ 2013-07-25 14:30... │
│ 9 ╎ 13 ╎ 2 ╎ Test check message ╎ 2013-07-25 14:3... ╎ 2013-07-25 14:31... │
│ 10 ╎ 13 ╎ 5 ╎ asdfdasfdasfdasfa ╎ 2013-07-25 14:4... ╎ 2013-07-25 14:42... │
│ 11 ╎ 16 ╎ 7 ╎ Hohohooh ╎ 2013-07-26 07:5... ╎ 2013-07-26 07:50... │
└────┴─────────┴─────────────┴─────────────────────┴────────────────────┴─────────────────────┘
I know how to count them the by for ex.: Geochecks.where(location_id: 3).count #=> 4 and thought about a loop which will do .where().count requests through the whole table and after that compare the results to find the biggest one, but I am pretty sure that there is a cleverer solution.
Desired output: The desired output should be a list of the location_id's in descending order. In this case it should be: 3, 2, 4, 5, 7
So, doing it with SQL as I pointed out in a comment would be rather complicated and requires good knowledge of SQL. But with a little time in rails c I found a way to do it in Rails!
The result of this query will be Locations not Geochecks, but I don't think it will be a problem for you.
Location.joins(:geochecks).order('COUNT(geochecks.id) DESC').group('location.id')
I think it should work:
Table.find(:all, :order => "location_id_count DESC")

Resources