Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

# how to permute multi arrays with different numbers of element?

2 views

### VZD

Mar 9, 2012, 5:30:33 PM3/9/12
to
numbers of element? I can make it manually, but what If you have more that
three arrays?

Thanks

# Perl permute multidimensional arrays
#

my @digits1 = qw(1 2);
my @digits2 = qw(1 2);
my @digits3 = qw(a b c);

foreach my \$i (@digits1) {
foreach my \$j (@digits2) {
foreach my \$k (@digits3) {
print "\$i\$j\$k\$l\n";
}
}
}

### Kiuhnm

Mar 9, 2012, 7:01:13 PM3/9/12
to
On 3/9/2012 23:30, VZD wrote:
> numbers of element? I can make it manually, but what If you have more that
> three arrays?

Here's an iterative way:

--->
sub count {
my \$cback = shift;
my @sizes = @_;
my @cnts = map { 0 } 0..\$#sizes;

\$cback->(@cnts);
while (1) {
my \$idx = \$#cnts;
\$cnts[\$idx]++;
while (\$idx > 0) {
last if \$cnts[\$idx] < \$sizes[\$idx];
\$cnts[\$idx] = 0;
\$cnts[--\$idx]++;
}
last if (!\$idx && \$cnts[0] == \$sizes[0]);
\$cback->(@cnts);
}
}

my @digits1 = qw(1 2);
my @digits2 = qw(1 2);
my @digits3 = qw(a b c);

my @arrays = (\@digits1, \@digits2, \@digits3);
&count(sub { say map { \$arrays[\$_]->[\$_[\$_]] } 0..\$#arrays },
map { scalar @{\$_} } @arrays);
<---

Kiuhnm

### Dr.Ruud

Mar 9, 2012, 7:55:04 PM3/9/12
to
On 2012-03-09 23:30, VZD wrote:

> numbers of element? I can make it manually, but what If you have more that
> three arrays?

Check out `perldoc -f glob`.

> my @digits1 = qw(1 2);
> my @digits2 = qw(1 2);
> my @digits3 = qw(a b c);

Numbered names raise a red flag.

--
Ruud

### Randal L. Schwartz

Mar 9, 2012, 8:15:34 PM3/9/12
to
>>>>> "Ruud" == Ruud <rvtol+...@xs4all.nl> writes:

>> my @digits1 = qw(1 2);
>> my @digits2 = qw(1 2);
>> my @digits3 = qw(a b c);

Ruud> Numbered names raise a red flag.

Some call it "code smell". I like that.

--
Randal L. Schwartz - Stonehenge Consulting Services, Inc. - +1 503 777 0095
<mer...@stonehenge.com> <URL:http://www.stonehenge.com/merlyn/>
Smalltalk/Perl/Unix consulting, Technical writing, Comedy, etc. etc.
See http://methodsandmessages.posterous.com/ for Smalltalk discussion

### Alan Curry

Mar 9, 2012, 9:55:36 PM3/9/12
to
This operation is called a "Cartesian product". Knowing that, it should be
easy to find several implementations.

--
Alan Curry

### Ben Morrow

Mar 9, 2012, 10:07:51 PM3/9/12
to

Quoth "VZD" <v...@vzd.vzd>:
> numbers of element? I can make it manually, but what If you have more that
> three arrays?

Hmm, well, since noone's given the obvious answer yet...

my @digits = (
[1, 2, 3],
[4, 5, 6],
[7, 8],
);

sub permute {
map {
my \$d = \$_;
@_ ? map "\$d\$_", permute(@_) : \$d;
} @{ +shift };
}

say for permute @digits;

Of course, you'll learn a lot more if you do your own homework.

(I seem to keep finding situations where I want to be able to say

map my \$d { ... } ...

, and I believe the 'my' is enough to stop it being ambiguous. Hmmm.)

Ben

### Martijn Lievaart

Mar 10, 2012, 2:05:54 AM3/10/12
to
On Sat, 10 Mar 2012 03:07:51 +0000, Ben Morrow wrote:

> (I seem to keep finding situations where I want to be able to say
>
> map my \$d { ... } ...
>
> , and I believe the 'my' is enough to stop it being ambiguous. Hmmm.)

I like it. Makes perfect sense.

M4

### Kiuhnm

Mar 10, 2012, 6:19:16 AM3/10/12
to
It depends on what VZD really wants. Does he want the elements in that
precise order?

Kiuhnm

### Kiuhnm

Mar 10, 2012, 6:24:29 AM3/10/12
to
On 3/10/2012 4:07, Ben Morrow wrote:
> (I seem to keep finding situations where I want to be able to say
>
> map my \$d { ... } ...
>
> , and I believe the 'my' is enough to stop it being ambiguous. Hmmm.)

That should apply to all list operators.

Kiuhnm

### Dr.Ruud

Mar 10, 2012, 10:19:40 AM3/10/12
to
On 2012-03-10 04:07, Ben Morrow wrote:
> Quoth "VZD"<v...@vzd.vzd>:

>> numbers of element? I can make it manually, but what If you have more that
>> three arrays?
>
> Hmm, well, since noone's given the obvious answer yet...

Was glob too obvious?

perl -wle'print for glob "{1,2,3}{4,5,6}{7,8}"'

--
Ruud

### Dr.Ruud

Mar 10, 2012, 10:37:32 AM3/10/12
to
On 2012-03-10 02:15, Randal L. Schwartz wrote:
> Ruud:
>> vdz:

>>> my @digits1 = qw(1 2);
>>> my @digits2 = qw(1 2);
>>> my @digits3 = qw(a b c);
>>
>> Numbered names raise a red flag.
>
> Some call it "code smell". I like that.

1. Numbered names smell.
2. Numbered names are code smell.
3. Numbered names make your code smell.
4. Code with numbered names smells.

I still prefer my n-n r-r pattern.
(I would translate "pink panther" to "paarse panter",
though "pink" is normally "roze".)

--
Ruud

### Ben Morrow

Mar 10, 2012, 11:10:50 AM3/10/12
to

Quoth "Dr.Ruud" <rvtol+...@xs4all.nl>:
glob doesn't work with arbitrary strings. I suppose you could assume the
OP was only (ever going to be) permuting digits, but I generally dislike
solutions that involve quoting and reparsing. Besides, the question
asked for an arbtrary number of arrays, and I don't know that

glob join "",
map "{\$_}",
map { join ",", @\$_ }
@digits;

is much more concise than the solution I posted.

Ben

### xho...@gmail.com

Mar 10, 2012, 11:51:18 AM3/10/12
to
I haven't tried this on a newer perl, but at least on older ones this
method will get slow and beat the crap out of your hard drive as the list
gets longs. It checks whether each string exists as a filename, but the
results of that check are ignored.

Xho

--
The costs of publication of this article were defrayed in part by the
this fact.

### Dr.Ruud

Mar 10, 2012, 11:51:32 AM3/10/12
to
On 2012-03-10 17:10, Ben Morrow wrote:
> Ruud:
>> Ben:
>>> vdz:

>>>> different numbers of element? I can make it manually, but what If
>>>> you have more that three arrays?
>>>
>>> Hmm, well, since noone's given the obvious answer yet...
>>
>> Was glob too obvious?
>>
>> perl -wle'print for glob "{1,2,3}{4,5,6}{7,8}"'
>
> glob doesn't work with arbitrary strings. I suppose you could assume the
> OP was only (ever going to be) permuting digits, but I generally dislike
> solutions that involve quoting and reparsing. Besides, the question
> asked for an arbtrary number of arrays, and I don't know that
>
> glob join "",
> map "{\$_}",
> map { join ",", @\$_ }
> @digits;
>
> is much more concise than the solution I posted.

Good points. It easily gets ugly:

perl -wle '
my @digits = ( [ 1, 2, 3 ], [ 4, 5, 6 ], [ 7, "8,X" ] );
print for glob join "",
map "{\$_}",
map join( ",", map quotemeta, @\$_ ),
@digits;
'

--
Ruud

### Dr.Ruud

Mar 10, 2012, 12:13:25 PM3/10/12
to
On 2012-03-10 17:51, xho...@gmail.com wrote:
> "Dr.Ruud"<rvtol+...@xs4all.nl> wrote:

>> perl -wle'print for glob "{1,2,3}{4,5,6}{7,8}"'
>
> I haven't tried this on a newer perl, but at least on older ones this
> method will get slow and beat the crap out of your hard drive as the list
> gets longs. It checks whether each string exists as a filename, but the
> results of that check are ignored.

Why do you think it would go to disk?

<quote src=`perldoc -f glob`>
If non-empty braces are the only wildcard characters used in
the "glob", no filenames are matched, but potentially many
strings are returned.
</quote>

Still, see Ben's reasons to avoid glob.

--
Ruud

### Ben Morrow

Mar 10, 2012, 12:33:43 PM3/10/12
to

Quoth "Dr.Ruud" <rvtol+...@xs4all.nl>:
Let's have a look, shall we?

~% ktrace -tn perl -e'glob "{1,2}{3,4}"'
~% kdump
<snip>
34066 perl NAMI "13"
34066 perl NAMI "14"
34066 perl NAMI "23"
34066 perl NAMI "24"
~%

So, yes, it goes to the disk, whether it needed to or not. (This is
5.12.2.)

Ben

### Kiuhnm

Mar 10, 2012, 1:10:53 PM3/10/12
to
On 3/10/2012 4:07, Ben Morrow wrote:
> Hmm, well, since noone's given the obvious answer yet...
>
> my @digits = (
> [1, 2, 3],
> [4, 5, 6],
> [7, 8],
> );
>
> sub permute {
> map {
> my \$d = \$_;
> @_ ? map "\$d\$_", permute(@_) : \$d;
> } @{ +shift };
> }
>
> say for permute @digits;

Here's a more efficient version:

--->
sub count {
my \$str = shift;
for (@{+shift}) {
@_ ? count("\$str\$_", @_) : say "\$str\$_"
}
}

count("", @digits);
<---

Kiuhnm

### Dr.Ruud

Mar 10, 2012, 1:23:35 PM3/10/12
to
On 2012-03-10 18:33, Ben Morrow wrote:
> Ruud:
>> xhoster:

>>> I haven't tried this on a newer perl, but at least on older ones this
>>> method will get slow and beat the crap out of your hard drive as the list
>>> gets longs. It checks whether each string exists as a filename, but the
>>> results of that check are ignored.
>>
>> Why do you think it would go to disk?
>>
>> <quote src=`perldoc -f glob`>
>> If non-empty braces are the only wildcard characters used in
>> the "glob", no filenames are matched, but potentially many
>> strings are returned.
>> </quote>
>
> Let's have a look, shall we?
>
> ~% ktrace -tn perl -e'glob "{1,2}{3,4}"'
> ~% kdump
> <snip>
> 34066 perl NAMI "13"
> 34066 perl NAMI "14"
> 34066 perl NAMI "23"
> 34066 perl NAMI "24"
> ~%
>
> So, yes, it goes to the disk, whether it needed to or not. (This is
> 5.12.2.)

Bug?

--
Ruud

### Peter J. Holzer

Mar 10, 2012, 3:04:44 PM3/10/12
to
On 2012-03-10 17:13, Dr.Ruud <rvtol+...@xs4all.nl> wrote:
> On 2012-03-10 17:51, xho...@gmail.com wrote:
>> "Dr.Ruud"<rvtol+...@xs4all.nl> wrote:
>
>>> perl -wle'print for glob "{1,2,3}{4,5,6}{7,8}"'
>>
>> I haven't tried this on a newer perl, but at least on older ones this
^^^^^^^^^^
>> method will get slow and beat the crap out of your hard drive as the list
>> gets longs. It checks whether each string exists as a filename, but the
>> results of that check are ignored.
>
> Why do you think it would go to disk?

Because older ones *do* go to disk?

% strace perl -wle'print for glob "{1,2,3}{4,5,6}{7,8}"'
[...]
lstat64("147", 0xbf910610) = -1 ENOENT (No such file or directory)
lstat64("148", 0xbf910610) = -1 ENOENT (No such file or directory)
lstat64("157", 0xbf910610) = -1 ENOENT (No such file or directory)
lstat64("158", 0xbf910610) = -1 ENOENT (No such file or directory)
lstat64("167", 0xbf910610) = -1 ENOENT (No such file or directory)
lstat64("168", 0xbf910610) = -1 ENOENT (No such file or directory)
lstat64("247", 0xbf910610) = -1 ENOENT (No such file or directory)
lstat64("248", 0xbf910610) = -1 ENOENT (No such file or directory)
lstat64("257", 0xbf910610) = -1 ENOENT (No such file or directory)
lstat64("258", 0xbf910610) = -1 ENOENT (No such file or directory)
lstat64("267", 0xbf910610) = -1 ENOENT (No such file or directory)
lstat64("268", 0xbf910610) = -1 ENOENT (No such file or directory)
lstat64("347", 0xbf910610) = -1 ENOENT (No such file or directory)
lstat64("348", 0xbf910610) = -1 ENOENT (No such file or directory)
lstat64("357", 0xbf910610) = -1 ENOENT (No such file or directory)
lstat64("358", 0xbf910610) = -1 ENOENT (No such file or directory)
lstat64("367", 0xbf910610) = -1 ENOENT (No such file or directory)
lstat64("368", 0xbf910610) = -1 ENOENT (No such file or directory)
write(1, "147\n", 4147
) = 4
write(1, "148\n", 4148
) = 4
write(1, "157\n", 4157
) = 4
[...]

% perl -v

This is perl, v5.10.1 (*) built for i486-linux-gnu-thread-multi
(with 56 registered patches, see perl -V for more detail)

><quote src=`perldoc -f glob`>
> If non-empty braces are the only wildcard characters used in
> the "glob", no filenames are matched, but potentially many
> strings are returned.
></quote>

This sentence isn't there in 5.10.1. If newer perls don't try to stat
the files any more (note that "no filenames are matched" doesn't
necessarily imply this), then the change was made after 5.10.1

hp

--
_ | Peter J. Holzer | Deprecating human carelessness and
|_|_) | Sysadmin WSR | ignorance has no successful track record.
| | | h...@hjp.at |
__/ | http://www.hjp.at/ | -- Bill Code on as...@irtf.org
0 new messages