Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > Ruby > Delete elements in array, break, and keep changes?

Reply
Thread Tools

Delete elements in array, break, and keep changes?

 
 
Joe Buck
Guest
Posts: n/a
 
      12-31-2009
I have an array of a lot elements that I need to cluster (they are
latitudes and longitudes).

As I iterate the array I want to remove elements that I have already
clustered.

Currently I've tried using Array::reject! and Array::delete_if. It
works. I can further optimize by breaking from the delete_if/reject!
block if certiain conditions are met.

Here is the issue, if I call break in the block, all of the changes to
the array are lost.

Is there a way to break from the block but still delete/reject elements
in the array?
--
Posted via http://www.ruby-forum.com/.

 
Reply With Quote
 
 
 
 
Ehsanul Hoque
Guest
Posts: n/a
 
      01-01-2010


> I have an array of a lot elements that I need to cluster (they are
> latitudes and longitudes).
>=20
> As I iterate the array I want to remove elements that I have already
> clustered.
>=20


In this case=2C it looks like Array#shift might work=2C though I'm not sure=
I totally understand your requirements. Something like:

until long_lat_array.empty?
long_lat =3D long_lat_array.shift
cluster(long_lat)
end

Hope I'm not missing your issue.

- Ehsan
=20
__________________________________________________ _______________
Hotmail: Powerful Free email with security by Microsoft.
http://clk.atdmt.com/GBL/go/171222986/direct/01/=

 
Reply With Quote
 
 
 
 
Joe Buck
Guest
Posts: n/a
 
      01-01-2010
Ehsan,

Thanks for the help. Unfortunately I don't think that will work as it
removes the first element in the array.

What I need is an Array::delete_if or Array::reject! call that allows me
to break from the block while still removing elements.

My solution is to use a second array to keep the indices of all removed
elements. I can then iterate through the second array after the first
loop and remove the elements. I'm guessing reject! and delete_if do this
as well. It could be more efficient but it works.

Thanks!
--
Posted via http://www.ruby-forum.com/.

 
Reply With Quote
 
Phillip Gawlowski
Guest
Posts: n/a
 
      01-01-2010
On 01.01.2010 17:45, Joe Buck wrote:
> Ehsan,
>
> Thanks for the help. Unfortunately I don't think that will work as it
> removes the first element in the array.


def copy_and_shift_array array
temp_array = array # or perform a deep copy, if you are worried about
# about the first array's integrity.
temp_array.each do |element|
return element if condition_met?
end
end

Array#shift is useful here *because* it gives you the first Array
element in an easily accessible format (the actual Object in the Array),
so that you can perform your checks and other magic, before storing it
someplace else.

Note: Above code is untested, but should work, at least in principle.

(I'm always a foggy when it comes to blocks and variable assignment in
Ruby, despite many ruby-talk discussions about scope in Ruby).

--
Phillip Gawlowski

 
Reply With Quote
 
pharrington
Guest
Posts: n/a
 
      01-01-2010
On Jan 1, 11:45*am, Joe Buck <semle2...@hotmail.com> wrote:
> Ehsan,
>
> Thanks for the help. Unfortunately I don't think that will work as it
> removes the first element in the array.
>
> What I need is an Array::delete_if or Array::reject! call that allows me
> to break from the block while still removing elements.
>
> My solution is to use a second array to keep the indices of all removed
> elements. I can then iterate through the second array after the first
> loop and remove the elements. I'm guessing reject! and delete_if do this
> as well. It could be more efficient but it works.
>
> Thanks!
> --
> Posted viahttp://www.ruby-forum.com/.


Without knowing the point of what you're trying to do, this sounds
like what you have in mind:

array = [] # or whatev
process_array = true
array.reject!(x) do
if process_array
conditional_code_for x
else
false
end
 
Reply With Quote
 
pharrington
Guest
Posts: n/a
 
      01-01-2010
On Jan 1, 2:18*pm, pharrington <xenogene...@gmail.com> wrote:
> On Jan 1, 11:45*am, Joe Buck <semle2...@hotmail.com> wrote:
>
>
>
>
>
> > Ehsan,

>
> > Thanks for the help. Unfortunately I don't think that will work as it
> > removes the first element in the array.

>
> > What I need is an Array::delete_if or Array::reject! call that allows me
> > to break from the block while still removing elements.

>
> > My solution is to use a second array to keep the indices of all removed
> > elements. I can then iterate through the second array after the first
> > loop and remove the elements. I'm guessing reject! and delete_if do this
> > as well. It could be more efficient but it works.

>
> > Thanks!
> > --
> > Posted viahttp://www.ruby-forum.com/.

>
> Without knowing the point of what you're trying to do, this sounds
> like what you have in mind:
>
> array = [] # or whatev
> process_array = true
> array.reject!(x) do
> * if process_array
> * * conditional_code_for x
> * else
> * * false
> end


Also, is the reject! really the bottleneck in your app? We obviously
don't want to intentionally write sub-optimal code, but do not
optimize what's not slowing you down.
 
Reply With Quote
 
pharrington
Guest
Posts: n/a
 
      01-01-2010
On Jan 1, 2:19*pm, pharrington <xenogene...@gmail.com> wrote:
> On Jan 1, 2:18*pm, pharrington <xenogene...@gmail.com> wrote:
>
>
>
>
>
> > On Jan 1, 11:45*am, Joe Buck <semle2...@hotmail.com> wrote:

>
> > > Ehsan,

>
> > > Thanks for the help. Unfortunately I don't think that will work as it
> > > removes the first element in the array.

>
> > > What I need is an Array::delete_if or Array::reject! call that allowsme
> > > to break from the block while still removing elements.

>
> > > My solution is to use a second array to keep the indices of all removed
> > > elements. I can then iterate through the second array after the first
> > > loop and remove the elements. I'm guessing reject! and delete_if do this
> > > as well. It could be more efficient but it works.

>
> > > Thanks!
> > > --
> > > Posted viahttp://www.ruby-forum.com/.

>
> > Without knowing the point of what you're trying to do, this sounds
> > like what you have in mind:

>
> > array = [] # or whatev
> > process_array = true
> > array.reject!(x) do
> > * if process_array
> > * * conditional_code_for x
> > * else
> > * * false
> > end

>
> Also, is the reject! really the bottleneck in your app? We obviously
> don't want to intentionally write sub-optimal code, but do not
> optimize what's not slowing you down.


wow array.reject! do |x| i don't know basic ruby syntax today...

Or if you really want to avoid even iterating over each element:

original_array = []
new_array = []

original_array.each {|x| new_array << x unless conditional_code_for
(x)}

But again, what precisely are you doing? Is the deletion code really
your bottleneck? And if it is, I'm almost certain that using a more
appropriate structure than an array would be the way to go.
 
Reply With Quote
 
Joe Buck
Guest
Posts: n/a
 
      01-01-2010
Alright, I won't hide you from the details. I have a map (google maps
API) with data points (100,000+).

I'm doing server side clustering of the points to limit the amount of
data I send to the client (I'm using the Ruby On Rails framework).

I start out with an array of 100,000 spots. Each spot is a hash with a
:lat and :lng. I need to iterate through the array and group the spots
into clusters. I break the world up into 30/30 degree clusters, so I
have 72 clusters to put the spots in.

The spots are ordered by longitude.

Here is the code (do you use code snippet tags here?). Note that
'listings' is the array of spots ordered by longitude.

#---------------------------------------------------------------------
for i in (0..72)

# Move to the next block.
bNextRow = (i%nRows == 0 && i!=0)
cLatLngBox.topRightLat = bNextRow ? 90 : cLatLngBox.topRightLat-size
cLatLngBox.topRightLng = bNextRow ? (cLatLngBox.topRightLng+size) :
cLatLngBox.topRightLng
cLatLngBox.botLeftLat = bNextRow ? 90-size :
(cLatLngBox.botLeftLat-size)
cLatLngBox.botLeftLng = bNextRow ? (cLatLngBox.botLeftLng+size) :
cLatLngBox.botLeftLng

# Holds the index of each spot we added to a cluster. We will remove
these
# from the listing when done.
cRemove = []

# Our new cluster.
cluster = {:lat=>0, :lng=>0, :size=>0}

# Iterate through all the spots, adding them to clusters.
listings.each_with_index do |listing, h|
if cLatLngBox.is_in_box?(listing[:lat], listing[:lng])

# Add to the cluster.
cluster[:size]+=1
cluster[:lat]+=listing[:lat].to_f
cluster[:lng]+=listing[:lng].to_f

# Tag the spot for removal.
cRemove << h
else
# We cheat here. Because the spots are ordered by longitude
(-180 to 180) we'll check
# if the spot longitude exceeds our current max. If it does
we're done with this loop.
if listing[:lng].to_f > cLatLngBox.topRightLng
break
end
end
end

# Remove all the items that were clustered.
cRemove.each do |index|
listings.delete_at(index)
end
#---------------------------------------------------------------------

This is faster than not removing the items. But I'd like to remove them
while I'm in the above loop, but still have the ability to break.
--
Posted via http://www.ruby-forum.com/.

 
Reply With Quote
 
Joe Buck
Guest
Posts: n/a
 
      01-01-2010
Sorry for the terrible formatting. As another example, here is C++ code
that would do what I want using iterators.


typedef std::vector<cSpot> spots_t;
spots_t cSpots;

// Fill cSpots here ...

CLatLngBox cLatLngBox;

for(int i=0; i<72; i++)
{
// Move cLatLngBox to the next block ..

// Our new cluster.
CCluster cCluster;

// Iterate points.
spots_t::iterator itr = cSpots.begin ();
for(itr; itr!=cSpots.end()
{
if(cLatLngBox.is_in_box(*itr))
{
// Add to cluster.

// This is where we remove the spot.
itr = cSpots.erase(itr);
}
else
{
if((*itr).lng > cLatLngBox.lng)
{
// Done with the inner loop.
break;
}

// Next spot.
itr++;
}
}
}
--
Posted via http://www.ruby-forum.com/.

 
Reply With Quote
 
Brian Candler
Guest
Posts: n/a
 
      01-01-2010
Array#delete_if appears to be completely borked when used with 'break'.

>> a = [5,6,7,8,9,10]

=> [5, 6, 7, 8, 9, 10]
>> a.delete_if { |x| break if x > 8; x < 7 }

=> nil
>> a

=> [7, 8, 7, 8, 9, 10]
>>


I have opened a ticket:
http://redmine.ruby-lang.org/issues/show/2545

In the mean time you could do something like this:

class Array
def safe_delete_if
i = 0
while i < length
if yield self[i]
slice!(i,1)
else
i += 1
end
end
end
end
--
Posted via http://www.ruby-forum.com/.

 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
How keep python socket alive for ever by setting Keep alive flag. hisan Python 1 06-25-2012 05:30 PM
Is there any way to delete Total Access and still keep Accelerator Howard H. Computer Support 2 01-19-2006 06:28 PM
XQuery how to keep order of elements? paul.rusu@gmail.com XML 7 12-14-2005 09:22 AM
keep form elements enabled on "back" request Dani Javascript 5 06-28-2005 10:25 PM
Using DHTML and INLINE tables -- want to keep relevant elements visible Jason Williamson Javascript 0 11-30-2003 02:09 PM



Advertisments
 



1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57