Algorithmic complexity of this algorithm to find all ordered permutations of length X
Clash Royale CLAN TAG#URR8PPP
.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty margin-bottom:0;
up vote
1
down vote
favorite
I have written a recursive function to generate the list of all ordered permutations of length X for a list of chars.
For instance: ['a', 'b', 'c', 'd'] with X=2 will give [['a', 'a'], ['a', 'b'], ['a', 'c'], ['a', 'd'], ['b', 'a'], ['b', 'b'], ..., ['d', 'd']]
I'm not sure about its algorithmic complexity though (at least I know it's pretty horrible). I would say it's something around:
O(X * N^(L + X))
(where L is the number of different chars, 4 here because we have 'A', 'B', 'C', 'D', and X the length of the permutations we want to generate). Because I have 2 nested loops, which will be run X times (well, X-1 because of the special case when X = 1). Is it correct?
def generate_permutations(symbols, permutations_length):
if permutations_length == 1:
return [[symbol] for symbol in symbols]
tails = generate_permutations(symbols, permutations_length-1)
permutations =
for symbol in symbols:
for tail in tails:
permutation = [symbol] + tail
permutations.append(permutation)
return permutations
print(generate_permutations(['a', 'b', 'c', 'd'], 2))
By the way: I know this is not idiomatic Python and I apologize if it's ugly but it's just some prototyping I'm doing before writing this code in a different, less expressive language. And I also know that I could use itertools.permutations to do this task. By the way, I'd be interested if someone happens to know the algorithmic complexity of itertool's permutations
function.
python algorithm reinventing-the-wheel combinatorics complexity
add a comment |Â
up vote
1
down vote
favorite
I have written a recursive function to generate the list of all ordered permutations of length X for a list of chars.
For instance: ['a', 'b', 'c', 'd'] with X=2 will give [['a', 'a'], ['a', 'b'], ['a', 'c'], ['a', 'd'], ['b', 'a'], ['b', 'b'], ..., ['d', 'd']]
I'm not sure about its algorithmic complexity though (at least I know it's pretty horrible). I would say it's something around:
O(X * N^(L + X))
(where L is the number of different chars, 4 here because we have 'A', 'B', 'C', 'D', and X the length of the permutations we want to generate). Because I have 2 nested loops, which will be run X times (well, X-1 because of the special case when X = 1). Is it correct?
def generate_permutations(symbols, permutations_length):
if permutations_length == 1:
return [[symbol] for symbol in symbols]
tails = generate_permutations(symbols, permutations_length-1)
permutations =
for symbol in symbols:
for tail in tails:
permutation = [symbol] + tail
permutations.append(permutation)
return permutations
print(generate_permutations(['a', 'b', 'c', 'd'], 2))
By the way: I know this is not idiomatic Python and I apologize if it's ugly but it's just some prototyping I'm doing before writing this code in a different, less expressive language. And I also know that I could use itertools.permutations to do this task. By the way, I'd be interested if someone happens to know the algorithmic complexity of itertool's permutations
function.
python algorithm reinventing-the-wheel combinatorics complexity
"And I also know that I could use itertools.permutations to do this task." So why didn't you?
â Mast
Apr 27 at 11:25
For the sake of the exercise and to learn how to do things by myself.
â Matthieu
Apr 27 at 11:53
add a comment |Â
up vote
1
down vote
favorite
up vote
1
down vote
favorite
I have written a recursive function to generate the list of all ordered permutations of length X for a list of chars.
For instance: ['a', 'b', 'c', 'd'] with X=2 will give [['a', 'a'], ['a', 'b'], ['a', 'c'], ['a', 'd'], ['b', 'a'], ['b', 'b'], ..., ['d', 'd']]
I'm not sure about its algorithmic complexity though (at least I know it's pretty horrible). I would say it's something around:
O(X * N^(L + X))
(where L is the number of different chars, 4 here because we have 'A', 'B', 'C', 'D', and X the length of the permutations we want to generate). Because I have 2 nested loops, which will be run X times (well, X-1 because of the special case when X = 1). Is it correct?
def generate_permutations(symbols, permutations_length):
if permutations_length == 1:
return [[symbol] for symbol in symbols]
tails = generate_permutations(symbols, permutations_length-1)
permutations =
for symbol in symbols:
for tail in tails:
permutation = [symbol] + tail
permutations.append(permutation)
return permutations
print(generate_permutations(['a', 'b', 'c', 'd'], 2))
By the way: I know this is not idiomatic Python and I apologize if it's ugly but it's just some prototyping I'm doing before writing this code in a different, less expressive language. And I also know that I could use itertools.permutations to do this task. By the way, I'd be interested if someone happens to know the algorithmic complexity of itertool's permutations
function.
python algorithm reinventing-the-wheel combinatorics complexity
I have written a recursive function to generate the list of all ordered permutations of length X for a list of chars.
For instance: ['a', 'b', 'c', 'd'] with X=2 will give [['a', 'a'], ['a', 'b'], ['a', 'c'], ['a', 'd'], ['b', 'a'], ['b', 'b'], ..., ['d', 'd']]
I'm not sure about its algorithmic complexity though (at least I know it's pretty horrible). I would say it's something around:
O(X * N^(L + X))
(where L is the number of different chars, 4 here because we have 'A', 'B', 'C', 'D', and X the length of the permutations we want to generate). Because I have 2 nested loops, which will be run X times (well, X-1 because of the special case when X = 1). Is it correct?
def generate_permutations(symbols, permutations_length):
if permutations_length == 1:
return [[symbol] for symbol in symbols]
tails = generate_permutations(symbols, permutations_length-1)
permutations =
for symbol in symbols:
for tail in tails:
permutation = [symbol] + tail
permutations.append(permutation)
return permutations
print(generate_permutations(['a', 'b', 'c', 'd'], 2))
By the way: I know this is not idiomatic Python and I apologize if it's ugly but it's just some prototyping I'm doing before writing this code in a different, less expressive language. And I also know that I could use itertools.permutations to do this task. By the way, I'd be interested if someone happens to know the algorithmic complexity of itertool's permutations
function.
python algorithm reinventing-the-wheel combinatorics complexity
edited Apr 27 at 12:16
Mast
7,32763484
7,32763484
asked Apr 27 at 10:13
Matthieu
112
112
"And I also know that I could use itertools.permutations to do this task." So why didn't you?
â Mast
Apr 27 at 11:25
For the sake of the exercise and to learn how to do things by myself.
â Matthieu
Apr 27 at 11:53
add a comment |Â
"And I also know that I could use itertools.permutations to do this task." So why didn't you?
â Mast
Apr 27 at 11:25
For the sake of the exercise and to learn how to do things by myself.
â Matthieu
Apr 27 at 11:53
"And I also know that I could use itertools.permutations to do this task." So why didn't you?
â Mast
Apr 27 at 11:25
"And I also know that I could use itertools.permutations to do this task." So why didn't you?
â Mast
Apr 27 at 11:25
For the sake of the exercise and to learn how to do things by myself.
â Matthieu
Apr 27 at 11:53
For the sake of the exercise and to learn how to do things by myself.
â Matthieu
Apr 27 at 11:53
add a comment |Â
1 Answer
1
active
oldest
votes
up vote
1
down vote
accepted
def generate_permutations(symbols, permutations_length):
These are not permutations. They are Cartesian products. In addition, calling the function generate_something
suggests that what's returned might be a generator, which is probably what you want for a function which returns a stupendously large data structure, but is not what you get from this function.
for symbol in symbols:
for tail in tails:
permutation = [symbol] + tail
permutations.append(permutation)
If you use extend
instead of append
then you give better hints as to how much underlying buffers might need to be increased:
for tail in tails:
result.extend([symbol] + tail for symbol in symbols)
Performance: with an alphabet of size $L$ let $T_L(X)$ be the cost of calling this function for products of length $X$. Then $T_L(1) = L$ and $T_L(X+1) = T_L(X) + L L^X (X+2)$ assuming that constructing the list [symbol] + tail
takes time proportional to its length and extending the list of results take amortised constant time per element added. This gives $Theta(L^XX)$ complexity.
The same complexity but much better memory efficiency can be achieved with a true generator approach which is based on the fact that all you really need to do is count to $L^X$ and convert into base $L$.
Thanks a lot for this explanation! And I agree that generate_something was not the best way to name it. May I ask how you would do the same thing with a generator instead?
â Matthieu
Apr 27 at 11:55
@Matthieu: suppose that instead of'a', 'b', 'c', 'd'
your elements are0, 1, 2, 3
and the Cartesian products are00, 01, 02, 03, 10, 11, 12, 13, 20, 21, 22, 23, 30, 31, 32, 33
. Does that make it clear what I mean by counting to 16 and converting into base 4?
â Peter Taylor
Apr 27 at 12:37
Yes, I get it! Thanks
â Matthieu
Apr 27 at 12:57
add a comment |Â
1 Answer
1
active
oldest
votes
1 Answer
1
active
oldest
votes
active
oldest
votes
active
oldest
votes
up vote
1
down vote
accepted
def generate_permutations(symbols, permutations_length):
These are not permutations. They are Cartesian products. In addition, calling the function generate_something
suggests that what's returned might be a generator, which is probably what you want for a function which returns a stupendously large data structure, but is not what you get from this function.
for symbol in symbols:
for tail in tails:
permutation = [symbol] + tail
permutations.append(permutation)
If you use extend
instead of append
then you give better hints as to how much underlying buffers might need to be increased:
for tail in tails:
result.extend([symbol] + tail for symbol in symbols)
Performance: with an alphabet of size $L$ let $T_L(X)$ be the cost of calling this function for products of length $X$. Then $T_L(1) = L$ and $T_L(X+1) = T_L(X) + L L^X (X+2)$ assuming that constructing the list [symbol] + tail
takes time proportional to its length and extending the list of results take amortised constant time per element added. This gives $Theta(L^XX)$ complexity.
The same complexity but much better memory efficiency can be achieved with a true generator approach which is based on the fact that all you really need to do is count to $L^X$ and convert into base $L$.
Thanks a lot for this explanation! And I agree that generate_something was not the best way to name it. May I ask how you would do the same thing with a generator instead?
â Matthieu
Apr 27 at 11:55
@Matthieu: suppose that instead of'a', 'b', 'c', 'd'
your elements are0, 1, 2, 3
and the Cartesian products are00, 01, 02, 03, 10, 11, 12, 13, 20, 21, 22, 23, 30, 31, 32, 33
. Does that make it clear what I mean by counting to 16 and converting into base 4?
â Peter Taylor
Apr 27 at 12:37
Yes, I get it! Thanks
â Matthieu
Apr 27 at 12:57
add a comment |Â
up vote
1
down vote
accepted
def generate_permutations(symbols, permutations_length):
These are not permutations. They are Cartesian products. In addition, calling the function generate_something
suggests that what's returned might be a generator, which is probably what you want for a function which returns a stupendously large data structure, but is not what you get from this function.
for symbol in symbols:
for tail in tails:
permutation = [symbol] + tail
permutations.append(permutation)
If you use extend
instead of append
then you give better hints as to how much underlying buffers might need to be increased:
for tail in tails:
result.extend([symbol] + tail for symbol in symbols)
Performance: with an alphabet of size $L$ let $T_L(X)$ be the cost of calling this function for products of length $X$. Then $T_L(1) = L$ and $T_L(X+1) = T_L(X) + L L^X (X+2)$ assuming that constructing the list [symbol] + tail
takes time proportional to its length and extending the list of results take amortised constant time per element added. This gives $Theta(L^XX)$ complexity.
The same complexity but much better memory efficiency can be achieved with a true generator approach which is based on the fact that all you really need to do is count to $L^X$ and convert into base $L$.
Thanks a lot for this explanation! And I agree that generate_something was not the best way to name it. May I ask how you would do the same thing with a generator instead?
â Matthieu
Apr 27 at 11:55
@Matthieu: suppose that instead of'a', 'b', 'c', 'd'
your elements are0, 1, 2, 3
and the Cartesian products are00, 01, 02, 03, 10, 11, 12, 13, 20, 21, 22, 23, 30, 31, 32, 33
. Does that make it clear what I mean by counting to 16 and converting into base 4?
â Peter Taylor
Apr 27 at 12:37
Yes, I get it! Thanks
â Matthieu
Apr 27 at 12:57
add a comment |Â
up vote
1
down vote
accepted
up vote
1
down vote
accepted
def generate_permutations(symbols, permutations_length):
These are not permutations. They are Cartesian products. In addition, calling the function generate_something
suggests that what's returned might be a generator, which is probably what you want for a function which returns a stupendously large data structure, but is not what you get from this function.
for symbol in symbols:
for tail in tails:
permutation = [symbol] + tail
permutations.append(permutation)
If you use extend
instead of append
then you give better hints as to how much underlying buffers might need to be increased:
for tail in tails:
result.extend([symbol] + tail for symbol in symbols)
Performance: with an alphabet of size $L$ let $T_L(X)$ be the cost of calling this function for products of length $X$. Then $T_L(1) = L$ and $T_L(X+1) = T_L(X) + L L^X (X+2)$ assuming that constructing the list [symbol] + tail
takes time proportional to its length and extending the list of results take amortised constant time per element added. This gives $Theta(L^XX)$ complexity.
The same complexity but much better memory efficiency can be achieved with a true generator approach which is based on the fact that all you really need to do is count to $L^X$ and convert into base $L$.
def generate_permutations(symbols, permutations_length):
These are not permutations. They are Cartesian products. In addition, calling the function generate_something
suggests that what's returned might be a generator, which is probably what you want for a function which returns a stupendously large data structure, but is not what you get from this function.
for symbol in symbols:
for tail in tails:
permutation = [symbol] + tail
permutations.append(permutation)
If you use extend
instead of append
then you give better hints as to how much underlying buffers might need to be increased:
for tail in tails:
result.extend([symbol] + tail for symbol in symbols)
Performance: with an alphabet of size $L$ let $T_L(X)$ be the cost of calling this function for products of length $X$. Then $T_L(1) = L$ and $T_L(X+1) = T_L(X) + L L^X (X+2)$ assuming that constructing the list [symbol] + tail
takes time proportional to its length and extending the list of results take amortised constant time per element added. This gives $Theta(L^XX)$ complexity.
The same complexity but much better memory efficiency can be achieved with a true generator approach which is based on the fact that all you really need to do is count to $L^X$ and convert into base $L$.
answered Apr 27 at 11:31
Peter Taylor
14k2454
14k2454
Thanks a lot for this explanation! And I agree that generate_something was not the best way to name it. May I ask how you would do the same thing with a generator instead?
â Matthieu
Apr 27 at 11:55
@Matthieu: suppose that instead of'a', 'b', 'c', 'd'
your elements are0, 1, 2, 3
and the Cartesian products are00, 01, 02, 03, 10, 11, 12, 13, 20, 21, 22, 23, 30, 31, 32, 33
. Does that make it clear what I mean by counting to 16 and converting into base 4?
â Peter Taylor
Apr 27 at 12:37
Yes, I get it! Thanks
â Matthieu
Apr 27 at 12:57
add a comment |Â
Thanks a lot for this explanation! And I agree that generate_something was not the best way to name it. May I ask how you would do the same thing with a generator instead?
â Matthieu
Apr 27 at 11:55
@Matthieu: suppose that instead of'a', 'b', 'c', 'd'
your elements are0, 1, 2, 3
and the Cartesian products are00, 01, 02, 03, 10, 11, 12, 13, 20, 21, 22, 23, 30, 31, 32, 33
. Does that make it clear what I mean by counting to 16 and converting into base 4?
â Peter Taylor
Apr 27 at 12:37
Yes, I get it! Thanks
â Matthieu
Apr 27 at 12:57
Thanks a lot for this explanation! And I agree that generate_something was not the best way to name it. May I ask how you would do the same thing with a generator instead?
â Matthieu
Apr 27 at 11:55
Thanks a lot for this explanation! And I agree that generate_something was not the best way to name it. May I ask how you would do the same thing with a generator instead?
â Matthieu
Apr 27 at 11:55
@Matthieu: suppose that instead of
'a', 'b', 'c', 'd'
your elements are 0, 1, 2, 3
and the Cartesian products are 00, 01, 02, 03, 10, 11, 12, 13, 20, 21, 22, 23, 30, 31, 32, 33
. Does that make it clear what I mean by counting to 16 and converting into base 4?â Peter Taylor
Apr 27 at 12:37
@Matthieu: suppose that instead of
'a', 'b', 'c', 'd'
your elements are 0, 1, 2, 3
and the Cartesian products are 00, 01, 02, 03, 10, 11, 12, 13, 20, 21, 22, 23, 30, 31, 32, 33
. Does that make it clear what I mean by counting to 16 and converting into base 4?â Peter Taylor
Apr 27 at 12:37
Yes, I get it! Thanks
â Matthieu
Apr 27 at 12:57
Yes, I get it! Thanks
â Matthieu
Apr 27 at 12:57
add a comment |Â
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f193066%2falgorithmic-complexity-of-this-algorithm-to-find-all-ordered-permutations-of-len%23new-answer', 'question_page');
);
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
"And I also know that I could use itertools.permutations to do this task." So why didn't you?
â Mast
Apr 27 at 11:25
For the sake of the exercise and to learn how to do things by myself.
â Matthieu
Apr 27 at 11:53