ordered_concatenations.sf 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131
  1. #!/usr/bin/ruby
  2. # Daniel "Trizen" Șuteu
  3. # Date: 29 April 2019
  4. # https://github.com/trizen
  5. # Given an array of strings, find all the possible ordered concatenations.
  6. # For example, given the array ["1", "2", "3", "4", "5"], there are 16 different ways:
  7. # ["1", "2", "3", "4", "5"]
  8. # ["1", "2", "3", "45"]
  9. # ["1", "2", "34", "5"]
  10. # ["1", "2", "345"]
  11. # ["1", "23", "4", "5"]
  12. # ["1", "23", "45"]
  13. # ["1", "234", "5"]
  14. # ["1", "2345"]
  15. # ["12", "3", "4", "5"]
  16. # ["12", "3", "45"]
  17. # ["12", "34", "5"]
  18. # ["12", "345"]
  19. # ["123", "4", "5"]
  20. # ["123", "45"]
  21. # ["1234", "5"]
  22. # ["12345"]
  23. # In general, for a given array with `n` distict elements, there are `2^(n-1)` possibilities.
  24. # This problem is similar in flavor to the non-greedy text wrapping problem.
  25. # See also:
  26. # https://en.wikipedia.org/wiki/Line_wrap_and_word_wrap
  27. # https://trizenx.blogspot.com/2013/11/smart-word-wrap.html
  28. # Simpler solution:
  29. # https://github.com/trizen/sidef-scripts/blob/master/Math/consecutive_partitions.sf
  30. func create_tries(array) {
  31. var root = []
  32. for i in (^array) {
  33. root << [array.slice(0, i+1)..., __FUNC__(array.slice(i+1))]
  34. }
  35. root
  36. }
  37. func make_paths (array) {
  38. var head = []
  39. while (array) {
  40. break if array[0].kind_of(Array)
  41. head << array.shift
  42. }
  43. var row = []
  44. for path in (array) {
  45. row << Hash(head.join, __FUNC__(path))
  46. }
  47. row ? row : head.join
  48. }
  49. func combine(root, hash) {
  50. var row = []
  51. hash.each{|key,value|
  52. root << key
  53. if (value.kind_of(Array)) {
  54. for item in (value) {
  55. row << __FUNC__(root, item)
  56. }
  57. }
  58. else {
  59. row << (root..., value)
  60. }
  61. root.pop
  62. }
  63. row
  64. }
  65. func normalize(array) {
  66. var normalized = []
  67. for item in (array) {
  68. if (item.kind_of(Array)) {
  69. normalized << __FUNC__(item)...
  70. }
  71. else {
  72. normalized << array
  73. break
  74. }
  75. }
  76. normalized
  77. }
  78. func ordered_concatenations(array) {
  79. var tries = create_tries(array)
  80. var paths = []
  81. for group in (tries) {
  82. paths << make_paths(group)
  83. }
  84. var combinations = []
  85. while (paths) {
  86. if (paths[0].kind_of(Array)) {
  87. paths << paths.shift...
  88. next
  89. }
  90. var path = paths.shift
  91. combinations << combine([], path)
  92. }
  93. normalize(combinations).map { .grep { _ != "" } }
  94. }
  95. var array = %w(1 2 3 4 5)
  96. ordered_concatenations(array).each{ .say }