Noob 'why doesn't this work' question

Hi and greetings to all group members!

I'm a new Ruby user with a background in Applescript, Hypertalk
(Supercard), and a little Unix. I was intrigued by Matt Neuburg's
article about Applescript and Ruby, and that's what got me reading some
intro books on Ruby. I just bought Textmate and I am lovin' it!

Anyway, I am wondering why this seemingly simple script fails:

sizeList = [0,1,2,3,4,5,6]
countarray = [3,4,6]
countarray.each {|x| sizeList.delete_at(x)}

what I want to happen is that sizelist gets deleted at the positions
specified in countArray, but the result I am getting is:

0
1
2
4
6

and the expected result should be 0,1,2,5, right?
What gives?

TIA,
vince

Mac OS X 10.5.2, G5 Quad, Textmate editor, ruby 1.86

···

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

Every time you delete an element, all the values to the right are
shifted one position. What you are doing essentially is:

irb(main):001:0> a = [0,1,2,3,4,5,6]
=> [0, 1, 2, 3, 4, 5, 6]
irb(main):002:0> a.delete_at(3)
=> 3
irb(main):003:0> a
=> [0, 1, 2, 4, 5, 6]
irb(main):004:0> a.delete_at(4)
=> 5
irb(main):005:0> a
=> [0, 1, 2, 4, 6]
irb(main):006:0> a.delete_at(6)
=> nil
irb(main):007:0> a
=> [0, 1, 2, 4, 6]

After the first delete_at, the elements 4,5 and 6 are shifted to fill the space
of the deleted element. So now, the element at index 4 is not the 4, it's the 5.
After those two deletions, the array no longer holds an element with index 6, so
the last deletion does nothing.

Hope this helps,

Jesus.

···

On Mon, Apr 14, 2008 at 5:47 PM, Vincent Angeloni <nospam7272@mac.com> wrote:

Hi and greetings to all group members!

I'm a new Ruby user with a background in Applescript, Hypertalk
(Supercard), and a little Unix. I was intrigued by Matt Neuburg's
article about Applescript and Ruby, and that's what got me reading some
intro books on Ruby. I just bought Textmate and I am lovin' it!

Anyway, I am wondering why this seemingly simple script fails:

sizeList = [0,1,2,3,4,5,6]
countarray = [3,4,6]
countarray.each {|x| sizeList.delete_at(x)}

what I want to happen is that sizelist gets deleted at the positions
specified in countArray, but the result I am getting is:

0
1
2
4
6

and the expected result should be 0,1,2,5, right?
What gives?

Vincent Angeloni wrote:

Hi and greetings to all group members!

I'm a new Ruby user with a background in Applescript, Hypertalk
(Supercard), and a little Unix. I was intrigued by Matt Neuburg's
article about Applescript and Ruby, and that's what got me reading some
intro books on Ruby. I just bought Textmate and I am lovin' it!

Anyway, I am wondering why this seemingly simple script fails:

sizeList = [0,1,2,3,4,5,6]
countarray = [3,4,6]
countarray.each {|x| sizeList.delete_at(x)}

and the expected result should be 0,1,2,5, right?
What gives?

Start counting at 0

···

--
Posted via http://www.ruby-forum.com/\.

Actually no, when you #delete_at one element from an array, the
indexes of it get altered too:

You can interpret what is doing #each on countarray:

irb(main):001:0> sizeList = [0,1,2,3,4,5,6]
=> [0, 1, 2, 3, 4, 5, 6]
irb(main):002:0> sizeList.delete_at(3)
=> 3
irb(main):003:0> sizeList.delete_at(4)
=> 5
irb(main):004:0> sizeList.delete_at(6)
=> nil

So, each time you iterate over countarray and remove the indicated
position, sizeList gets updated, and thus, the next items in the
countarray no longer reference your expected positions.

Errr, sound complicated my explanation, anyone with a better written
one? :slight_smile:

HTH,

···

On Apr 14, 12:47 pm, Vincent Angeloni <nospam7...@mac.com> wrote:

Hi and greetings to all group members!

I'm a new Ruby user with a background in Applescript, Hypertalk
(Supercard), and a little Unix. I was intrigued by Matt Neuburg's
article about Applescript and Ruby, and that's what got me reading some
intro books on Ruby. I just bought Textmate and I am lovin' it!

Anyway, I am wondering why this seemingly simple script fails:

sizeList = [0,1,2,3,4,5,6]
countarray = [3,4,6]
countarray.each {|x| sizeList.delete_at(x)}

what I want to happen is that sizelist gets deleted at the positions
specified in countArray, but the result I am getting is:

0
1
2
4
6

and the expected result should be 0,1,2,5, right?
What gives?

--
Luis Lavena

When you delete_at(3), your new array looks like:

  sizeList[0] = 0
  sizeList[1] = 1
  sizeList[2] = 2
  sizeList[3] = 4
  sizeList[4] = 5
  sizeList[5] = 6

. . . because sizeList[3] = 3.

When you then delete_at(4), your new array looks like:

  sizeList[0] = 0
  sizeList[1] = 1
  sizeList[2] = 2
  sizeList[3] = 4
  sizeList[4] = 6

. . . because sizeList[4] = 5. Et cetera. Every time you delete an
element out of the middle, you shift everything to the right of it
leftward, basically.

You could try this:

  sizeList = [0,1,2,3,4,5,6]
  countarray = [6,4,3]
  countarray.each {|x| sizeList.delete_at(x)}

That would start at the far end of the array and work backwards, so that
positional shifts after a deleted element won't affect numbering for
stuff you want to delete later. If you can't guarantee that the numbers
in countarray will be in reverse numerical order when you get them, you
can sort them that way thusly:

  countarray = [3,6,4].sort.reverse

If you want to keep the array intact, rather than removing elements, and
just reset the values of specific elements to be "nothing", you could
instead do something like this:

  countarray.each {|x| sizeList = nil}

There are probably more elegant ways to do what you want -- and I'm not
entirely sure what you're trying to accomplish anyway -- but this might
help get you on the right track.

···

On Tue, Apr 15, 2008 at 12:47:21AM +0900, Vincent Angeloni wrote:

Hi and greetings to all group members!

I'm a new Ruby user with a background in Applescript, Hypertalk
(Supercard), and a little Unix. I was intrigued by Matt Neuburg's
article about Applescript and Ruby, and that's what got me reading some
intro books on Ruby. I just bought Textmate and I am lovin' it!

Anyway, I am wondering why this seemingly simple script fails:

sizeList = [0,1,2,3,4,5,6]
countarray = [3,4,6]
countarray.each {|x| sizeList.delete_at(x)}

what I want to happen is that sizelist gets deleted at the positions
specified in countArray, but the result I am getting is:

0
1
2
4
6

and the expected result should be 0,1,2,5, right?
What gives?

--
CCD CopyWrite Chad Perrin [ http://ccd.apotheon.org ]
Rudy Giuliani: "You have free speech so I can be heard."

What about this:

sizeList = [0,1,2,3,4,5,6]
countarray = [3,4,6]
countarray.sort.reverse.each {|x| sizeList.delete_at(x)}

Result: 0,1,2,5

···

On Apr 14, 5:47 pm, Vincent Angeloni <nospam7...@mac.com> wrote:

Hi and greetings to all group members!

I'm a new Ruby user with a background in Applescript, Hypertalk
(Supercard), and a little Unix. I was intrigued by Matt Neuburg's
article about Applescript and Ruby, and that's what got me reading some
intro books on Ruby. I just bought Textmate and I am lovin' it!

Anyway, I am wondering why this seemingly simple script fails:

sizeList = [0,1,2,3,4,5,6]
countarray = [3,4,6]
countarray.each {|x| sizeList.delete_at(x)}

what I want to happen is that sizelist gets deleted at the positions
specified in countArray, but the result I am getting is:

0
1
2
4
6

and the expected result should be 0,1,2,5, right?
What gives?

TIA,
vince

Mac OS X 10.5.2, G5 Quad, Textmate editor, ruby 1.86

Luis Lavena wrote:

···

On Apr 14, 12:47 pm, Vincent Angeloni <nospam7...@mac.com> wrote:

countarray = [3,4,6]

and the expected result should be 0,1,2,5, right?
What gives?

Actually no, when you #delete_at one element from an array, the
indexes of it get altered too:

You can interpret what is doing #each on countarray:

irb(main):001:0> sizeList = [0,1,2,3,4,5,6]
=> [0, 1, 2, 3, 4, 5, 6]
irb(main):002:0> sizeList.delete_at(3)
=> 3
irb(main):003:0> sizeList.delete_at(4)
=> 5
irb(main):004:0> sizeList.delete_at(6)
=> nil

So, each time you iterate over countarray and remove the indicated
position, sizeList gets updated, and thus, the next items in the
countarray no longer reference your expected positions.

Errr, sound complicated my explanation, anyone with a better written
one? :slight_smile:

HTH,

Ah, yes. I knew it was something simple.
I'll just sort countarray so that the highest index value is first, and
perhaps that will take care of the problem!
Thank you.

vince
--
Posted via http://www.ruby-forum.com/\.

I'm not entirely sure what you're trying to accomplish anyway

I guess he is starting to _learn_ which could explain what he
is wanting to accomplish so examples don't necessarily need to
make much sense and his head will slowly fill up with
101 ways to achieve what he wants to have :wink:

···

--
Posted via http://www.ruby-forum.com/\.

sizeList = [0,1,2,3,4,5,6]
countarray = [3,4,6]
countarray.each {|x| sizeList.delete_at(x)}

Let's look at what's going on inside your .each block.
  The first iteration it will delete the sizeList[3]. ===> [0,1,2,4,5,6]
  The second iteration it will delete sizeList[4] ===> [0,1,2,4,6]
  The final iteration it will delete sizeList[6] ==> [0,1,2,4,6] #there
is no sizeList[6] - deleteAt returns nil.

Your indexs are changing each time you call delete_at.

-Stephen

···

On Tue, Apr 15, 2008 at 9:15 AM, Robin Pedersen <robinpeder@gmail.com> wrote:

On Apr 14, 5:47 pm, Vincent Angeloni <nospam7...@mac.com> wrote:
> Hi and greetings to all group members!
>
> I'm a new Ruby user with a background in Applescript, Hypertalk
> (Supercard), and a little Unix. I was intrigued by Matt Neuburg's
> article about Applescript and Ruby, and that's what got me reading some
> intro books on Ruby. I just bought Textmate and I am lovin' it!
>
> Anyway, I am wondering why this seemingly simple script fails:
>
> sizeList = [0,1,2,3,4,5,6]
> countarray = [3,4,6]
> countarray.each {|x| sizeList.delete_at(x)}
>
> what I want to happen is that sizelist gets deleted at the positions
> specified in countArray, but the result I am getting is:
>
> 0
> 1
> 2
> 4
> 6
>
> and the expected result should be 0,1,2,5, right?
> What gives?
>
> TIA,
> vince
>
> Mac OS X 10.5.2, G5 Quad, Textmate editor, ruby 1.86

What about this:

sizeList = [0,1,2,3,4,5,6]
countarray = [3,4,6]
countarray.sort.reverse.each {|x| sizeList.delete_at(x)}

Result: 0,1,2,5

Another approach would be: instead of deleting each item, put nil at
each specified array index. Then, after you're done iterating, delete
all the nils using Array#compact!, like so:

sizeList = [0,1,2,3,4,5,6]
countarray = [3,4,6]
countarray.each {|x| sizeList = nil}
sizeList.compact!

···

On Apr 14, 12:16 pm, Vincent Angeloni <nospam7...@mac.com> wrote:

Ah, yes. I knew it was something simple.
I'll just sort countarray so that the highest index value is first, and
perhaps that will take care of the problem!
Thank you.

Marc Heiler wrote:

I'm not entirely sure what you're trying to accomplish anyway

I guess he is starting to _learn_ which could explain what he
is wanting to accomplish so examples don't necessarily need to
make much sense and his head will slowly fill up with
101 ways to achieve what he wants to have :wink:

Basically, I'm trying to get a list of files/folders along with
a separate list of the sizes of said files. The array deletions
I asked about would be the deletion of files enclosed in folders
from the original file list and using the position of the items
in the file list to delete the corresponding array position in
the separate size list of those files.

And thanks to everyone who responded. 101 ways to do this would
be great, but I'll settle for 4 or 5. :wink:

This has been very helpful.

vince

···

--
Posted via http://www.ruby-forum.com/\.

Ah, yes. I knew it was something simple.
I'll just sort countarray so that the highest index value is first, and
perhaps that will take care of the problem!
Thank you.

Another approach would be: instead of deleting each item, put nil at
each specified array index. Then, after you're done iterating, delete
all the nils using Array#compact!, like so:

sizeList = [0,1,2,3,4,5,6]

Btw, the conventional way in Ruby is to use "size_list" instead of CamelCase for method and variable names.

countarray = [3,4,6]
countarray.each {|x| sizeList = nil}
sizeList.compact!

Yet another alternative is to delete based on /criteria/ and not /position/.

In this case that could be

# note, the array in the block is not the original
# array but contains entries to be deleted - it's
# only accidentally the same because of the way that
# size_list is built.
size_list.delete_if {|x| [3,4,6].include? x}

Or any other criterium.

Kind regards

  robert

···

On 14.04.2008 19:25, Karl von Laudermann wrote:

On Apr 14, 12:16 pm, Vincent Angeloni <nospam7...@mac.com> wrote:

# And thanks to everyone who responded. 101 ways to do this would
# be great, but I'll settle for 4 or 5. :wink:

i hope this catches up the 5th way :slight_smile:

ruby1.9 though,

irb(main):004:0> sizeList.group_by.with_index{|e,i| countarray.include? i}
=> {false=>[0, 1, 2, 5], true=>[3, 4, 6]}

fr here you can get what gets deleted,

irb(main):016:0> sizeList.group_by.with_index{|e,i| countarray.include? i}[true]
=> [3, 4, 6]

and what remains,

irb(main):017:0> sizeList.group_by.with_index{|e,i| countarray.include? i}[false]
=> [0, 1, 2, 5]

the beauty here is you can go slowly, and picture out and compare in advance what will be deleted and what will remain...

kind regards -botp

···

From: list-bounce@example.com

Another solution could be, instead of having 2 arrays, to have
a single array where each position contains all the info for
a file, maybe like an array or hash, and then delete based on
the size info. Example:

file_info = [["a.txt", 123], ["b.txt", 10000]]
file_info.delete_if {|x| x[1] > 1000}

will delete all entries whose size is bigger than 1000.

As a hash:

file_info = [{:name => "a.txt", :size => 123}, {:name => "b.txt",
:size => 10000}]
file_info.delete_if {|x| x[:size] > 1000}

or you could have a custom object if you need more complex modelling
of the file info.

Hope this helps,

Jesus.

···

On Tue, Apr 15, 2008 at 2:14 AM, Vincent Angeloni <nospam7272@mac.com> wrote:

Basically, I'm trying to get a list of files/folders along with
a separate list of the sizes of said files. The array deletions
I asked about would be the deletion of files enclosed in folders
from the original file list and using the position of the items
in the file list to delete the corresponding array position in
the separate size list of those files.

irb(main):001:0> a = [0,1,2,3,4,5,6]
=> [0, 1, 2, 3, 4, 5, 6]
irb(main):002:0> b = [3,4,6]
=> [3, 4, 6]
irb(main):003:0> c = a - b
=> [0, 1, 2, 5]
irb(main):004:0>

# irb(main):004:0> sizeList.group_by.with_index{|e,i|
# countarray.include? i}
# => {false=>[0, 1, 2, 5], true=>[3, 4, 6]}

6th way :slight_smile:

:0> sizeList.values_at(*(0..sizeList.size-1).to_a-countarray)
=> [0, 1, 2, 5]

this one plays w the indices, then uses values_at to get back to the contents.

kind regards -botp

···

From: Peña, Botp [mailto:botp@delmonte-phil.com]

# irb(main):001:0> a = [0,1,2,3,4,5,6]
# => [0, 1, 2, 3, 4, 5, 6]
# irb(main):002:0> b = [3,4,6]
# => [3, 4, 6]
# irb(main):003:0> c = a - b
# => [0, 1, 2, 5]

Hi Paul, the op meant that the array b contains indexes for a (and not contents as in your example)

kind regards -botp

···

From: Paul [mailto:Paul.McArdles@gmail.com]