Zsh Mailing List Archive
Messages sorted by: Reverse Date, Date, Thread, Author

Re: Sorting file names randomly

On Jul 24,  9:39am, DervishD wrote:
} >       for ((i=1; i <= $#; ++i)) { reply[i*RANDOM/32768+1]+=($argv[i]) }
}     Why is it better than my function?

It's shorter (which is one of the things you asked for), and it only
does array processing rather than building up and tearing down strings.

} Maybe this is faster than doing the '(e' thing?

More on this below.

} >       for ((i=1; i <= $#; ++i)) { h[$i.$RANDOM]=$argv[i] }
}     I understand this one better ;) That's another solution I thought
} of, but I assumed that if I used associative arrays, the order of
} elements would be the order in which they were inserted (which is
} not, I've discovered right now).
}     Anyway, the ordering of elements in an associative array is not
} very random if $RANDOM is not included in the key, and I don't
} understand it :?? How are associative arrays elements sorted?

Are you familiar with the concept of hash tables?  That's how nearly
all languages that have associative arrays, implement them, and in
many cases (e.g. Perl) they're even called "hashes" by the language.

You can think of the elements as being ordered by a set of numbers
computed by applying a simple algorithm to the ascii values of the
characters in the key strings.  It's actually a bit more complex than
that, but close enough.

On Jul 24, 10:37am, DervishD wrote:
}     How about this?:

Well ...

} function shuffle () {
}     setopt nullglob globdots rcexpandparam
}     reply=()
}     reply=($*)

Don't you mean $~* there?  Otherwise you have the problem with
multiple directories that you alluded to once before.

}     reply=($reply(e:'REPLY="${(l.5..0.)RANDOM} $REPLY"':))

This is wasteful in a number of ways.

First, the (l.5..0.) is just left-zero-padding $RANDOM, so rather than
force the shell parse that and work out what to do once for every file
name, it would be better to declare "local +h -Z 5 RANDOM" as I did.
(Just remember to seed RANDOM when making it local.)

Second, by using a glob qualifier, you're forcing the shell to stat()
every file name second time, after it has already been done once when
reply=($~*) is assigned [assuming $~* is what you meant].

Third, you're doing string concatenation, adding six bytes for each
file name.  If you're worried about exceeding argument limits, you
ought to be worried about how much extra memory that eats.

Fourth, you've eventually got to do this ...

}     reply=(${reply/#????? /})

... which has to copy every string in order to pattern-match it and
chop it up before assigning it back again, so you're roughly doubling
the memory needed right there, possibly as much as tripling it if I
recall correctly how array assignments are performed.

My hash solution isn't very much less memory intensive (if you skipped
the final assignment to the reply array and just printed the values it
would be better); but the += version is about as small a footprint as
you're going to get, because inserting array slices only copies the new
elements being inserted (everything else is moving of pointers to the
existing elements).

}     print -l $reply
}     return 0

Unless you expect "print" to fail, the "return 0" is redundant.

}     It does the globbing outside, and shuffles correctly. Any way of
} making the 'reply' assignments shorter?

You can eliminate the glob qualifier by using the "eval" trick I posted
on a different thread (placement of quotes and spaces is important):

eval 'reply=(' '$RANDOM '${(q)reply} ')'

However, you can't do fewer than three assignments.

On Jul 24, 10:40am, DervishD wrote:
} >     reply=($*)
} >     reply=($reply(e:'REPLY="${(l.5..0.)RANDOM} $REPLY"':))
} >     reply=(${(o)reply})
}     How could I avoid doing this? I cannot put the 'o' in the
} assignment above this one because it doesn't work, it seems to sort
} *before* applying the 'e' glob modifier).

Obviously the glob applies after any sorting in that second assignment.
The glob qualifier is being applied to the strings that *result* from
the parameter expansion; that's why you need the rcexpandparam option.

Messages sorted by: Reverse Date, Date, Thread, Author