Reputation: 18570
Main Question: What is the fastest way to insert an item into a list that is already sorted using Julia?
Currently, I do this:
v = [1, 2, 3, 5] #example list
x = 4 #value to insert
index = searchsortedfirst(v, x) #find index at which to insert x
insert!(v, index, x) #insert x at index
Bonus Question: What if I want to simultaneously ensure no duplicates?
Upvotes: 7
Views: 3116
Reputation: 29
For sorted arrays of structs a modified version of StefanKarpinski solution would look like the example below:
struct TimeEvent
date::Dates.DateTime
type::String
end
v = [
TimeEvent(DateTime("2019-03-01"),"data_release")
TimeEvent(DateTime("2019-02-01"),"data_release")
TimeEvent(DateTime("2019-05-01"),"data_release")
]
new_event=TimeEvent(DateTime("2019-04-01"),"data_release")
# Sort Events
sort!(v, by = v -> v.date, rev=true)
# Define Function
sortedStructInsert!(v::Vector, x) = (splice!(v,
searchsorted(v,x,by= v->v.date, rev=true), [x]); v)
# Call function
sortedStructInsert!(v, new_event)
4-element Vector{TimeEvent}:
TimeEvent(DateTime("2019-05-01T00:00:00"), "data_release")
TimeEvent(DateTime("2019-04-01T00:00:00"), "data_release")
TimeEvent(DateTime("2019-03-01T00:00:00"), "data_release")
TimeEvent(DateTime("2019-02-01T00:00:00"), "data_release")
The example below allows you to specify which field of the struct is the one that sorts, for a more generic implementation.
sortedStructInsert!(v::Vector, x,symbol) = (splice!(v,
searchsorted(v,x,by= v->getproperty(v,symbol), rev=true), [x]); v)
sortedStructInsert!(v, new_event, :date)
Upvotes: 0
Reputation: 33290
You can use searchsorted
to get the range of indices where the value occurs instead of just the first one and then use splice!
to replace the values in that range with a new set of values:
insert_and_dedup!(v::Vector, x) = (splice!(v, searchsorted(v,x), [x]); v)
That's a nice little one-liner that does what you want.
julia> v = [1, 2, 3, 3, 5];
julia> insert_and_dedup!(v, 4)
6-element Array{Int64,1}:
1
2
3
3
4
5
julia> insert_and_dedup!(v, 3)
5-element Array{Int64,1}:
1
2
3
4
5
This made me think that splice!
should handle the case where the replacement is a single value rather than an array, so I may add that feature.
Upvotes: 10