{"id":16697820,"url":"https://github.com/mmstick/permutate","last_synced_at":"2025-03-17T00:33:48.888Z","repository":{"id":57654294,"uuid":"67467440","full_name":"mmstick/permutate","owner":"mmstick","description":"Generic permutator written in Rust that permutates both lists of lists and singular lists using references.","archived":false,"fork":false,"pushed_at":"2019-05-02T15:57:05.000Z","size":38,"stargazers_count":15,"open_issues_count":1,"forks_count":2,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-03-09T01:29:50.669Z","etag":null,"topics":["algorithm","permutation","rust"],"latest_commit_sha":null,"homepage":"","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/mmstick.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2016-09-06T02:46:30.000Z","updated_at":"2020-10-07T15:03:52.000Z","dependencies_parsed_at":"2022-09-01T01:12:32.834Z","dependency_job_id":null,"html_url":"https://github.com/mmstick/permutate","commit_stats":null,"previous_names":[],"tags_count":4,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mmstick%2Fpermutate","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mmstick%2Fpermutate/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mmstick%2Fpermutate/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mmstick%2Fpermutate/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/mmstick","download_url":"https://codeload.github.com/mmstick/permutate/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":243835942,"owners_count":20355611,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["algorithm","permutation","rust"],"created_at":"2024-10-12T17:49:22.601Z","updated_at":"2025-03-17T00:33:47.992Z","avatar_url":"https://github.com/mmstick.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Permutate\n\nPermutate exists as both a library and application for permutating\ngeneric vectors or tuples of lists, as well as individual lists,\nusing an original Rust-based algorithm.\nIt has been developed primarily for the goal of inclusion within the\nRust implementation of the GNU Parallel program, and brace expansions\nwithin Redox's Ion shell.\n\nThe source code documentation may be found on\n[Docs.rs](https://docs.rs/permutate/).\n\n## Features\n\n- `bin-utils` - if set then the binary utilities are included.\n    - Set by default and is required by the `bin` and `bench` profiles.\n\n## Mechanics\n\nPermutations work by incrementing a vector of index counters,\nand returning a vector of references to the underlying data\n(unless the container owns the values and they are Copy).\nFor optimal usage, it is best to perform one iteration with the \n`next()` method, and follow up successive iterations with the\n`next_with_buffer()` method, so that you can re-use the previous\nvector allocation.\nIt is also possible to obtain the state of the internal index counters\nby using the `get_indexes()` method, and set the state with the\n`set_indexes` method.\n\n## Examples\n\nThese are a list of examples on how to use the library to manipulate\nvarious types of data.\nThe only thing we may need to ensure is that our list of strings is in the `Vec\u003c\u0026[\u0026str]\u003e` format.\n\n### An individual list: [\u0026[\u0026str]; 1]\n\n```rust\nextern crate permutate;\nuse permutate::{Permutator, PermutatorWrapper as _, Repeated};\nuse std::io::{self, Write};\n\nfn main() {\n    let list: \u0026[\u0026str] = \u0026[\"one\", \"two\", \"three\", \"four\"];\n    let list = [list];\n    let mut permutator = Permutator::\u003cRepeated\u003c_\u003e, _\u003e::new(\u0026list);\n\n    // iteration 1: re-utilizes the permutation buffer\n    // you may opt to re-utilize or not (see iteration 2)\n    if let Some(mut permutation) = permutator.next() {\n        // prints each element\n        for element in \u0026permutation {\n            println!(\"{:?}\", \u0026element);\n        }\n        // re-utilizes the permutation buffer\n        while let Some(permutation) = permutator.next_with_buffer(\u0026mut permutation) {\n            // prints each element\n            for element in permutation {\n                println!(\"{:?}\", \u0026element);\n            }\n        }\n    }\n}\n```\n\n### A vec of slices: `Vec\u003c\u0026[\u0026str]\u003e`\n\n```rust\nextern crate permutate;\nuse permutate::{Permutator, PermutatorWrapper as _};\nuse std::io::{self, Write};\n\nfn main() {\n    let lists = [\n        \u0026[\"one\", \"two\", \"three\"][..],\n        \u0026[\"four\", \"five\", \"six\"][..],\n        \u0026[\"seven\", \"eight\", \"nine\"][..],\n    ];\n    let mut permutator = Permutator::new(\u0026lists.to_vec());\n\n    // iteration 2: allocates a new buffer for each permutation\n    // you may opt to re-allocate or not (see iteration 1)\n    for permutation in permutator {\n        println!(\"{:?}\", \u0026permutation);\n    }\n}\n```\n\n### A Vector of Vector of Strings: `Vec\u003cVec\u003cString\u003e\u003e`\n\nThis is the most complicated example to accomplish because\nyou have to convert, essentially, a vector of a vector of vectors into\na slice of a slice of a slice,\nas the String type itself is a vector of characters.\n\n```rust\nextern crate permutate;\nuse permutate::{Permutator, PermutatorWrapper as _};\nuse std::io::{self, Write};\n\nfn main() {\n    let lists: Vec\u003cVec\u003cString\u003e\u003e = vec![\n        vec![\"one\".to_owned(), \"two\".to_owned(), \"three\".to_owned()],\n        vec![\"four\".to_owned(), \"five\".to_owned(), \"six\".to_owned()],\n        vec![\"seven\".to_owned(), \"eight\".to_owned(), \"nine\".to_owned()],\n    ];\n\n    // Convert the `Vec\u003cVec\u003cString\u003e\u003e` into a `Vec\u003cVec\u003c\u0026str\u003e\u003e`\n    let tmp: Vec\u003cVec\u003c\u0026str\u003e\u003e = lists.iter()\n        .map(|list| list.iter()\n            .map(AsRef::as_ref)\n            .collect::\u003cVec\u003c\u0026str\u003e\u003e()\n        )\n        .collect();\n\n    // Convert the `Vec\u003cVec\u003c\u0026str\u003e\u003e` into a `Vec\u003c\u0026[\u0026str]\u003e`\n    let vector_of_slices: Vec\u003c\u0026[\u0026str]\u003e = tmp.iter()\n        .map(AsRef::as_ref).collect();\n\n    // Initialize the Permutator\n    let mut permutator = Permutator::new(\u0026vector_of_slices);\n\n    // iteration 2: allocates a new buffer for each permutation\n    // you may opt to re-allocate or not (see iteration 1)\n    for permutation in permutator {\n        println!(\"{:?}\", \u0026permutation);\n    }\n}\n```\n\n### A tuple of slices: `(\u0026[\u0026str], \u0026[bool])`\n\n```rust\nextern crate permutate;\nuse permutate::{Permutator, PermutatorWrapper as _};\nuse std::io::{self, Write};\n\nfn main() {\n    let lists = (\n        \u0026[\"one\", \"two\", \"three\"][..],\n        \u0026[false, true][..],\n    );\n    let mut permutator = Permutator::new(\u0026lists);\n\n    // iteration 2: allocates a new buffer for each permutation\n    // you may opt to re-allocate or not (see iteration 1)\n    for permutation in permutator {\n        let (s, b): (\u0026str, bool) = permutation;\n        println!(\"{:?}\", \u0026(s, b));\n    }\n}\n```\nNote that the slice of booleans actually owns the booleans,\nand so they are `copy`ed at each permutation.\n\n## Application\n\nFollowing the spirit of the Rust and UNIX philosophy,\nI am also releasing this as it's own simple application to bring the\ncapabilities of the permutate to the command-line, because shell lives\nmatter.\nThe syntax is very much identical to GNU Parallel,\nso users of GNU Parallel will be right at home with this command.\n\n```sh\n$ permutate A B ::: C D ::: E F\nA C E\nA C F\nA D E\nA D F\nB C E\nB C F\nB D E\nB D F\n```\n\n```sh\n$ permutate -n A B ::: C D ::: E F\nACE\nACF\nADE\nADF\nBCE\nBCF\nBDE\nBDF\n```\n\nOther accepted syntaxes are:\n\n```sh\n$ permutate -f file file :::+ arg arg :::: file file ::::+ file file ::: arg arg\n\n```\n\n### Benchmark\n\nSo how fast is it?\ntry running `cargo bench` to see how fast it creates 10k permutations \nover string references, repeated over 10k iterations.  \nIt takes ~550us per iteration on my laptop \n(i7-4710HQ Quad Core capped at 1600MHz on ArchLinux), \nie. around 18M permutations per second\n(= 10k[permutations/iteration] * 10k[iterations] / 5.50[seconds]).\n\nAnother way of benchmarking it is to use the generated binary directly:\n```sh\n$ cargo build --release\n$ for char in A B C D E F G H I J; do echo $char \u003e\u003e A; done\n$ time target/release/permutate --benchmark -n -f A :::: A :::: A :::: A :::: A :::: A :::: A :::: A\n$ rm A\n```\nThis will also test for 100M permutations (10^8 permutations),\nthen you only need to divide 100,000,000 by the duration.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmmstick%2Fpermutate","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmmstick%2Fpermutate","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmmstick%2Fpermutate/lists"}