Howdy, Stranger!

It looks like you're new here. If you want to get involved, click one of these buttons!

Looping through an array / simple matching?

So I'm sure I'm missing a simple solution here but all I am finding is Harlowe's documentation for 'contains' and basic array use, and greyelf's samples on how to use array's. If I wanted to check 'are all the elements in array1 present in array2' how would I do that? (assuming I don't know the the exact lengths of array1 and array2)

I was thinking maybe something like
(if: $ar4 contains (...$ar4))[ar4 contained ...ar4]
(if: ...$ar4 is ...$ar4)[...ar4 is ...ar4]

but that didn't work (didn't expect it to but hoped there would be some overloaded functionality). The only loop I can find in Twine 2 anywhere is the live: stuff (not applicable) and the contains: that does an under-the-hood loop


  • edited November 2015
    Hadn't heard back regarding any implementation existing, so here's my solution for it:
    Call to function:
    (set: $ar1 to (array: "foo", "bar", "baz"))
    (set: $ar2 to (array: "foo", "baz", "baz"))
    (set: $ar3 to (array: "foo", "bar", "baz", "hex"))
    (set: $ar4 to (array: "foo", "bar", "baz"))
    (set: $g_fnArrayMatch_params to (array: $ar1, $ar2))
    (display:"fnArrayMatch")(if: $g_fnArrayMatch_success is true)[ERROR](else:)[CORRECT]
    (set: $g_fnArrayMatch_params to (array: $ar1, $ar3))
    (display:"fnArrayExactMatch")(if: $g_fnArrayMatch_success is true)[ERROR](else:)[CORRECT]
    (set: $g_fnArrayMatch_params to (array: $ar1, $ar4))
    (display:"fnArrayMatch")(if: $g_fnArrayMatch_success is true)[ERROR](else:)[CORRECT]

    The actual base function is fnArrayMatch, it checks that everything on the left exists in the right:
    {(set: $g_fnArrayMatch_success to true)
    Array: (print: $g_fnArrayMatch_params)
    * Param1: (print: $g_fnArrayMatch_params's 1st)
    * Param2: (print: ($g_fnArrayMatch_params's 1st)'s 1st) *
    (if: (($g_fnArrayMatch_params's 1st)'s 1st) is "NA")[
    (set: $g_errorCodes to (array: "Invalid input", "fnArrayMatch", "g_fnArrayMatch_params **(print: $g_fnArrayMatch_params)** was NA"))
    (set: $g_fnArrayMatch_success to false)
      (set: $l_TempArraySrc to $g_fnArrayMatch_params's 1st)
      (set: $l_TempArrayDst to $g_fnArrayMatch_params's 2nd)
      (display: "fnArrayMatchLoop")]
    (set: $l_TempArraySrc to (array: "NA"))
    (set: $l_TempArrayDst to (array: "NA"))
    (if: $g_showDebugArrows)[ [[fnArrayMatchLoop]] ]}

    And this calls the recursive function (fnArrayMatchLoop):
    {(if: ($l_TempArraySrc's length) > 0)[
    * Checking (print: ($l_TempArraySrc's last))
    (if: $l_TempArrayDst contains $l_TempArraySrc's last)[CONTAINS]
    (else:)[DOES NOT CONTAIN(set: $g_fnArrayMatch_success to false)]
    (if: $g_fnArrayMatch_success is true)[
    (if: ($l_TempArraySrc's length) > 1)[
    (set: $l_TempArraySrc to (subarray: $l_TempArraySrc, 1, ($l_TempArraySrc's length)-1))
    * Popped.  DeepCopy: $l_TempArraySrc  
    * Deep Copy Length: (print: ($l_TempArraySrc's length))
    (display: "fnArrayMatchLoop")

    And for an exact match just taking the slightly slower performance, faster coding solutions of calling the function from both directions (fnArrayExactMatch):
    {(set: $g_fnArrayMatch_success to true)
    (display: "fnArrayMatch")
    (if: $g_fnArrayMatch_success is true)[ 
    (set: $l_TempArraySrc to $g_fnArrayMatch_params's 1st)
    (set: $g_fnArrayMatch_params's 1st to $g_fnArrayMatch_params's 2nd)
    (set: $g_fnArrayMatch_params's 2nd to $l_TempArraySrc)
    (display: "fnArrayMatch")]
    (if: $g_showDebugArrows)[ [[fnArrayMatch]] ]}

    Not the prettiest or most optimal implementation for sure, but good enough and seems to work

    (Oh, the error code stuff in it can be removed, its an error handler / logger I'm building for myself)
  • (er: cleaned up fnArrayMatchLoop without comments and stuff)
    {(if: ($l_TempArraySrc's length) > 0)[
      (if: $l_TempArrayDst contains $l_TempArraySrc's last)[
        (if: $g_fnArrayMatch_success is true)[
          (if: ($l_TempArraySrc's length) > 1)[
             (set: $l_TempArraySrc to (subarray: $l_TempArraySrc, 1, ($l_TempArraySrc's length)-1))
             (display: "fnArrayMatchLoop")
    (else:)[(set: $g_fnArrayMatch_success to false)]
  • Sorry I missed this, but I've been away from the forum. There is a simpler way to do what you want using set arithmetic.

    $arr1 - $arr2 will return an array which contains just the elements from $arr1 which aren't in $arr2. So if $arr2 contains every element from $arr1 the result will be an empty array.

    To test if $arr2 contains every element in $arr1 you could do
    (if: $arr1 - $arr2 is (a:))[success]

    To test if $arr2 and $arr1 are identical you can do
    (if: $arr1 is $arr2)[success]

    Your version didn't work because of the ... before the arrays.

    In your example you print error if $ar1 and $ar4 match, but they seem to be identical. Is that a mistake?
Sign In or Register to comment.