PHP has usort and Java has the Comparator interface.
These allow you to create a simple function that compare two Objects, Strings, etc. without getting involved in the details of the sort implementation.
Generally, the comparison function looks something like this:
// Return value:
// Negative value: a before b
// Positive value: b before a
// Zero: strings are equal
function compare(String a, String b) {
return toLowerCase(a) - toLowerCase(b);
}
... and you can be as simple or as fancy as you like with your comparisons.
Is there anything in AutoIt that does this?
The documentation is great, and the Help File is great, but I cannot find anything that allows me to define a custom comparison function. (I will reimplement Quicksort if necessary, but with a framework as full-featured as AutoIt, I feel like I must just be overlooking something.)
"Is there anything in AutoIt that does this?"
Example as per _ArrayMultiColSort() :
#include <Array.au3>
#include "ArrayMultiColSort.au3"
Global Const $g_sHeaderRow = 'category|value'
Global Const $g_aSortOrder = [ _
[0, 'critical,important,regular'], _
[1, 1] _
]
Global $g_aArray = [ _
['critical', 7], _
['important', 2], _
['important', 6], _
['regular', 2], _
['critical', 5], _
['regular', 9] _
]
_ArrayMultiColSort($g_aArray, $g_aSortOrder)
_ArrayDisplay($g_aArray, #ScriptName, '', 0, Default, $g_sHeaderRow)
Returns:
critical 7
critical 5
important 6
important 2
regular 9
regular 2
While there does not seem to be anything build into AutoIt, continued research revealed several very useful libraries the community has created.
Below is one called _ArrayCustomSort.au3 by Erik Pilsits. Script has been copied at the end of this post for reference. Original can be found here:
https://www.autoitscript.com/forum/topic/83626-natural-order-string-comparison/
Usage:
#include <File.au3>
#include "_ArrayCustomSort.au3"
; Directory to list files
Local $dir = "C:\Windows"
Local $arr = _FileListToArray($dir, "*")
_ArrayDelete($arr, 0)
; Here is the name of the user-defined sorting function!
_ArrayCustomSort($arr, "_MyBasicStringCompare", 0)
_ArrayDisplay($arr)
; Now you can put all your crazy sorting logic in here!
Func _MyBasicStringCompare($s1, $s2)
Return StringCompare($s1, $s2)
EndFunc
Include Library:
#include-once
#include <Array.au3>
; #FUNCTION# ====================================================================================================================
; Name ..........: _ArrayCustomSort
; Description ...: Sort a 1D or 2D array on a specific index using the quicksort/insertionsort algorithms, based on a custom sorting function.
; Syntax ........: _ArrayCustomSort(Byref $avArray, $sSortFunc[, $iDescending = 0[, $iStart = 0[, $iEnd = 0[, $iSubItem = 0]]]])
; Parameters ....: $avArray - [in/out] Array to sort
; $sSortFunc - Name of custom sorting function. See Remarks for usage.
; $iDescending - [optional] If set to 1, sort descendingly
; $iStart - [optional] Index of array to start sorting at
; $iEnd - [optional] Index of array to stop sorting at
; $iSubItem - [optional] Sub-index to sort on in 2D arrays
; Return values .: Success - 1
; Failure - 0, sets #error:
; |1 - $avArray is not an array
; |2 - $iStart is greater than $iEnd
; |3 - $iSubItem is greater than subitem count
; |4 - $avArray has too many dimensions
; |5 - Invalid sort function
; Author ........: Erik Pilsits
; Modified ......: Erik Pilsits - removed IsNumber testing, LazyCoder - added $iSubItem option, Tylo - implemented stable QuickSort algo, Jos van der Zande - changed logic to correctly Sort arrays with mixed Values and Strings, Ultima - major optimization, code cleanup, removed $i_Dim parameter
; Remarks .......: Sorting function is called with two array elements as arguments. The function should return
; 0 if they are equal,
; -1 if element one comes before element two,
; 1 if element one comes after element two.
; Related .......:
; Link ..........:
; Example .......: No
; ===============================================================================================================================
Func _ArrayCustomSort(ByRef $avArray, $sSortFunc, $iDescending = 0, $iStart = 0, $iEnd = 0, $iSubItem = 0)
If Not IsArray($avArray) Then Return SetError(1, 0, 0)
If Not IsString($sSortFunc) Then Return SetError(5, 0, 0)
Local $iUBound = UBound($avArray) - 1
; Bounds checking
If $iEnd < 1 Or $iEnd > $iUBound Then $iEnd = $iUBound
If $iStart < 0 Then $iStart = 0
If $iStart > $iEnd Then Return SetError(2, 0, 0)
; Sort
Switch UBound($avArray, 0)
Case 1
__ArrayCustomQuickSort1D($avArray, $sSortFunc, $iStart, $iEnd)
If $iDescending Then _ArrayReverse($avArray, $iStart, $iEnd)
Case 2
Local $iSubMax = UBound($avArray, 2) - 1
If $iSubItem > $iSubMax Then Return SetError(3, 0, 0)
If $iDescending Then
$iDescending = -1
Else
$iDescending = 1
EndIf
__ArrayCustomQuickSort2D($avArray, $sSortFunc, $iDescending, $iStart, $iEnd, $iSubItem, $iSubMax)
Case Else
Return SetError(4, 0, 0)
EndSwitch
Return 1
EndFunc ;==>_ArrayCustomSort
; #INTERNAL_USE_ONLY#============================================================================================================
; Name...........: __ArrayCustomQuickSort1D
; Description ...: Helper function for sorting 1D arrays
; Syntax.........: __ArrayCustomQuickSort1D(ByRef $avArray, ByRef $sSortFunc, ByRef $iStart, ByRef $iEnd)
; Parameters ....: $avArray - Array to sort
; $sSortFunc - Name of sorting function.
; $iStart - Index of array to start sorting at
; $iEnd - Index of array to stop sorting at
; Return values .: None
; Author ........: Jos van der Zande, LazyCoder, Tylo, Ultima
; Modified.......: Erik Pilsits - removed IsNumber testing
; Remarks .......: For Internal Use Only
; Related .......:
; Link ..........;
; Example .......;
; ===============================================================================================================================
Func __ArrayCustomQuickSort1D(ByRef $avArray, ByRef $sSortFunc, ByRef $iStart, ByRef $iEnd)
If $iEnd <= $iStart Then Return
Local $vTmp
; InsertionSort (faster for smaller segments)
If ($iEnd - $iStart) < 15 Then
Local $i, $j
For $i = $iStart + 1 To $iEnd
$vTmp = $avArray[$i]
For $j = $i - 1 To $iStart Step -1
If (Call($sSortFunc, $vTmp, $avArray[$j]) >= 0) Then ExitLoop
$avArray[$j + 1] = $avArray[$j]
Next
$avArray[$j + 1] = $vTmp
Next
Return
EndIf
; QuickSort
Local $L = $iStart, $R = $iEnd, $vPivot = $avArray[Int(($iStart + $iEnd) / 2)]
Do
While (Call($sSortFunc, $avArray[$L], $vPivot) < 0)
$L += 1
WEnd
While (Call($sSortFunc, $avArray[$R], $vPivot) > 0)
$R -= 1
WEnd
; Swap
If $L <= $R Then
$vTmp = $avArray[$L]
$avArray[$L] = $avArray[$R]
$avArray[$R] = $vTmp
$L += 1
$R -= 1
EndIf
Until $L > $R
__ArrayCustomQuickSort1D($avArray, $sSortFunc, $iStart, $R)
__ArrayCustomQuickSort1D($avArray, $sSortFunc, $L, $iEnd)
EndFunc ;==>__ArrayCustomQuickSort1D
; #INTERNAL_USE_ONLY#============================================================================================================
; Name...........: __ArrayCustomQuickSort2D
; Description ...: Helper function for sorting 2D arrays
; Syntax.........: __ArrayCustomQuickSort2D(ByRef $avArray, ByRef $sSortFunc, ByRef $iStep, ByRef $iStart, ByRef $iEnd, ByRef $iSubItem, ByRef $iSubMax)
; Parameters ....: $avArray - Array to sort
; $iStep - Step size (should be 1 to sort ascending, -1 to sort descending!)
; $iStart - Index of array to start sorting at
; $iEnd - Index of array to stop sorting at
; $iSubItem - Sub-index to sort on in 2D arrays
; $iSubMax - Maximum sub-index that array has
; Return values .: None
; Author ........: Jos van der Zande, LazyCoder, Tylo, Ultima
; Modified.......: Erik Pilsits - removed IsNumber testing
; Remarks .......: For Internal Use Only
; Related .......:
; Link ..........;
; Example .......;
; ===============================================================================================================================
Func __ArrayCustomQuickSort2D(ByRef $avArray, ByRef $sSortFunc, ByRef $iStep, ByRef $iStart, ByRef $iEnd, ByRef $iSubItem, ByRef $iSubMax)
If $iEnd <= $iStart Then Return
; QuickSort
Local $i, $vTmp, $L = $iStart, $R = $iEnd, $vPivot = $avArray[Int(($iStart + $iEnd) / 2)][$iSubItem]
Do
While ($iStep * Call($sSortFunc, $avArray[$L][$iSubItem], $vPivot) < 0)
$L += 1
WEnd
While ($iStep * Call($sSortFunc, $avArray[$R][$iSubItem], $vPivot) > 0)
$R -= 1
WEnd
; Swap
If $L <= $R Then
For $i = 0 To $iSubMax
$vTmp = $avArray[$L][$i]
$avArray[$L][$i] = $avArray[$R][$i]
$avArray[$R][$i] = $vTmp
Next
$L += 1
$R -= 1
EndIf
Until $L > $R
__ArrayCustomQuickSort2D($avArray, $sSortFunc, $iStep, $iStart, $R, $iSubItem, $iSubMax)
__ArrayCustomQuickSort2D($avArray, $sSortFunc, $iStep, $L, $iEnd, $iSubItem, $iSubMax)
EndFunc ;==>__ArrayCustomQuickSort2D
Related
Lets say I have an array declaration looking like this
array[1..5] of int: temp = [1,0,5,0,3];
Is there a way to initiate a new array looking the same as temp but without the 0's? The result would look like the following
[1,5,3]
or sort the array in such a way that the 0's would be either in the beginning or in the end of the array, which would be
[0,0,1,5,3]
or
[1,5,3,0,0]
Thanks
Even though Axel has answered this, I'll show another approach which - in my book is a little neater.
Case 1: the array ("temp") is a constant array.
Then one can simply write
array[int] of int: temp2 = [temp[i] | i in index_set(temp) where temp[i] != 0];
MiniZinc 2 (in contrast to version 1.*) don't need the size declaration if it can be calculated; it suffices to just use "array[int]". Also, "index_set" is used to be a little more general, e.g. to handle cases where the indices are from 0..4 (see the commented line).
Case 2: the array ("s") is an array of decision variables
If the array to handle is decision variables, we don't know (per definition) how many 0's there are and must rely on the alternative variant, namely to sort the array. One can then use the "sort" function, as shown in the model.
include "globals.mzn";
% constant
array[1..5] of int: temp = [1,0,5,0,3];
% array[0..4] of int: temp = array1d(0..4, [1,0,5,0,3]);
array[int] of int: temp2 = [temp[i] | i in index_set(temp) where temp[i] != 0];
% decision variables
array[1..5] of var int: s;
array[1..5] of var int: s2 = sort(s); % NOT CORRECT, see model below
solve satisfy;
constraint
s = [1,0,5,0,3]
;
% show our variables
output
[
"temp: \(temp)\n",
"temp2: \(temp2)\n",
"s: \(s)\n",
"s2: \(s2)\n",
];
Update
For the stable version of decision variables, this works what I can see. It calculating the position where to place this number depending on if "s[i]" is 0 or not. Not very pretty though.
int: n = 5;
array[1..n] of var 0..5: s;
array[1..n] of var lb_array(s)..ub_array(s): s2;
solve satisfy;
constraint
s = [1,0,5,0,3] /\
forall(i in 1..n) (
if s[i] != 0 then
s2[sum([s[j]!=0 | j in 1..i-1])+1] = s[i]
else
s2[sum([s[j]!=0 | j in 1..n]) + sum([s[j]=0 | j in 1..i-1])+1 ] = 0
endif
)
;
output
[
"s: \(s)\n",
"s2: \(s2)\n",
]
;
The output is
s: [1, 0, 5, 0, 3]
s2: [1, 5, 3, 0, 0]
Using MiniZinc 2, this can be done as follows:
array[1..5] of int: temp = [1,0,5,0,3];
% calculate upper bound of temp index
int: i_max = max(index_set(temp));
% use array comprehension to count non-zero elements
int: temp_non_zero = sum([1 | i in 1..i_max where temp[i] != 0]);
% copy non-zero elements to new array
array[1..temp_non_zero] of int: temp2 = [temp[i] | i in 1..i_max where temp[i] != 0];
% calculate upper bound for temp2 index
int: i2_max = max(index_set(temp2));
solve satisfy;
% show our variables
output
["\ni_max=" ++ show(i_max)]
++ ["\ni2_max=" ++ show(i2_max)]
++ ["\n" ++ show(temp2[i]) | i in 1..i2_max]
;
Another alternative:
A 1:1 mapping between the two arrays is established as an array of unique index values (= array positions). These indices are then sorted. The comparison weights elements higher if they point to a zero. Thus, the zero values are shifted to the back while leaving the order of the non-zero elements unchanged.
int: n = 5;
int: INF = 99999; % infinity
array[1..n] of var 0..5: s;
array[1..n] of var 1..n: map;
array[1..n] of var 0..5: s2;
solve satisfy;
% set s[]
constraint
s = [1,0,5,0,3]
;
% 1:1 mapping between s[] and s2[]
constraint
forall (i in 1..n) (
exists(j in 1..n) (
map[j] = i
)
)
;
constraint
forall(i in 1..n) (
s2[i] = s[map[i]]
)
;
% sort the map and move zero values to the back
constraint
forall(i in 1..n-1) (
(if s2[i] != 0 then map[i] else INF endif) <=
(if s2[i+1] != 0 then map[i+1] else INF endif)
)
;
output
[
"s: \(s)\n",
"map: \(map)\n",
"s2: \(s2)\n",
]
;
Output:
s: [1, 0, 5, 0, 3]
map: [1, 3, 5, 4, 2]
s2: [1, 5, 3, 0, 0]
Im just trying to do a simple ImageSearch script usig AutoIt. But I cant get it to work propely even tho Im sure the image Im searching for is on the screen.
Here is my code:
#include <ImageSearch.au3>
global $x , $y
HotKeySet ("{F1}",StartScriptc)
HotKeySet ("{F2}",StopScript)
While 1
Sleep(200)
WEnd
Func StartScriptc()
;WinActivate("MyWindow")
FindPicture()
EndFunc
Func StopScript()
Exit
EndFunc
Func FindPicture()
While 1
ConsoleWrite ("Before search" & #CRLF)
$search = _ImageSearch("test2.bmp",0,$x,$y,50)
if $search = 1 Then
ConsoleWrite ("Found it!" & #CRLF)
Else
ConsoleWrite ("Fail!" & #CRLF)
EndIf
WEnd
EndFunc
When I run this code I get the "Before Search" output but it never passes to the lines after the _ImageSearch() function. Instead the scipt just ends (I guess its a crash)
Here is the output I get:
Before search
14:10:51 AutoIt3.exe ended.rc:-1073741819
14:10:51 AutoIt3Wrapper Finished.
Exit code: 3221225477 Time: 9.844
I am not the author of ImageSearch.au3, its from http://www.autoitscript.com/forum/topic/65748-image-search-library/.
I have tried both the 32 and 64 bit versions without success. I put the DLL and ImageSearch script into the same folder as my .bmp file and test script.
This Image Search library works for me.
#include-once
; ------------------------------------------------------------------------------
;
; AutoIt Version: 3.0
; Language: English
; Description: Functions that assist with Image Search
; Require that the ImageSearchDLL.dll be loadable
;
; ------------------------------------------------------------------------------
;===============================================================================
;
; Description: Find the position of an image on the desktop
; Syntax: _ImageSearchArea, _ImageSearch
; Parameter(s):
; $findImage - the image to locate on the desktop
; $tolerance - 0 for no tolerance (0-255). Needed when colors of
; image differ from desktop. e.g GIF
; $resultPosition - Set where the returned x,y location of the image is.
; 1 for centre of image, 0 for top left of image
; $x $y - Return the x and y location of the image
;
; Return Value(s): On Success - Returns 1
; On Failure - Returns 0
;
; Note: Use _ImageSearch to search the entire desktop, _ImageSearchArea to specify
; a desktop region to search
;
;===============================================================================
Func _ImageSearch($findImage,$resultPosition,ByRef $x, ByRef $y,$tolerance)
return _ImageSearchArea($findImage,$resultPosition,0,0,#DesktopWidth,#DesktopHeight,$x,$y,$tolerance)
EndFunc
Func _ImageSearchArea($findImage,$resultPosition,$x1,$y1,$right,$bottom,ByRef $x, ByRef $y, $tolerance)
;MsgBox(0,"asd","" & $x1 & " " & $y1 & " " & $right & " " & $bottom)
if $tolerance>0 then $findImage = "*" & $tolerance & " " & $findImage
$result = DllCall("ImageSearchDLL.dll","str","ImageSearch","int",$x1,"int",$y1,"int",$right,"int",$bottom,"str",$findImage)
; If error exit
if $result[0]="0" then return 0
; Otherwise get the x,y location of the match and the size of the image to
; compute the centre of search
$array = StringSplit($result[0],"|")
$x=Int(Number($array[2]))
$y=Int(Number($array[3]))
if $resultPosition=1 then
$x=$x + Int(Number($array[4])/2)
$y=$y + Int(Number($array[5])/2)
endif
return 1
EndFunc
;===============================================================================
;
; Description: Wait for a specified number of seconds for an image to appear
;
; Syntax: _WaitForImageSearch, _WaitForImagesSearch
; Parameter(s):
; $waitSecs - seconds to try and find the image
; $findImage - the image to locate on the desktop
; $tolerance - 0 for no tolerance (0-255). Needed when colors of
; image differ from desktop. e.g GIF
; $resultPosition - Set where the returned x,y location of the image is.
; 1 for centre of image, 0 for top left of image
; $x $y - Return the x and y location of the image
;
; Return Value(s): On Success - Returns 1
; On Failure - Returns 0
;
;
;===============================================================================
Func _WaitForImageSearch($findImage,$waitSecs,$resultPosition,ByRef $x, ByRef $y,$tolerance)
$waitSecs = $waitSecs * 1000
$startTime=TimerInit()
While TimerDiff($startTime) < $waitSecs
sleep(100)
$result=_ImageSearch($findImage,$resultPosition,$x, $y,$tolerance)
if $result > 0 Then
return 1
EndIf
WEnd
return 0
EndFunc
;===============================================================================
;
; Description: Wait for a specified number of seconds for any of a set of
; images to appear
;
; Syntax: _WaitForImagesSearch
; Parameter(s):
; $waitSecs - seconds to try and find the image
; $findImage - the ARRAY of images to locate on the desktop
; - ARRAY[0] is set to the number of images to loop through
; ARRAY[1] is the first image
; $tolerance - 0 for no tolerance (0-255). Needed when colors of
; image differ from desktop. e.g GIF
; $resultPosition - Set where the returned x,y location of the image is.
; 1 for centre of image, 0 for top left of image
; $x $y - Return the x and y location of the image
;
; Return Value(s): On Success - Returns the index of the successful find
; On Failure - Returns 0
;
;
;===============================================================================
Func _WaitForImagesSearch($findImage,$waitSecs,$resultPosition,ByRef $x, ByRef $y,$tolerance)
$waitSecs = $waitSecs * 1000
$startTime=TimerInit()
While TimerDiff($startTime) < $waitSecs
for $i = 1 to $findImage[0]
sleep(100)
$result=_ImageSearch($findImage[$i],$resultPosition,$x, $y,$tolerance)
if $result > 0 Then
return $i
EndIf
Next
WEnd
return 0
EndFunc
I'm trying to take the first block of code from this link: http://www.geeksforgeeks.org/dynamic-programming-subset-sum-problem/
Copied and pasted below:
bool isSubsetSum(int set[], int n, int sum)
{
// Base Cases
if (sum == 0)
return true;
if (n == 0 && sum != 0)
return false;
// If last element is greater than sum, then ignore it
if (set[n-1] > sum)
return isSubsetSum(set, n-1, sum);
/* else, check if sum can be obtained by any of the following
(a) including the last element
(b) excluding the last element */
return isSubsetSum(set, n-1, sum) || isSubsetSum(set, n-1, sum-set[n-1]);
}
And translate it into a recursive VBA function that I plan on calling from a Sub.
So far I have:
Function SubSum(source(), n As Integer, sum)
If sum = 0 Then
SubSum = True
End If
If (n = 0 And sum <> 0) Then
SubSum = False
End If
If source(n - 1) > sum Then
SubSum = SubSum(source, n - 1, sum)
End If
SubSum = (SubSum(source, n - 1, sum) Or SubSum(source, n - 1, sum - source(n - 1)))
End Function
My issue is that returning a value in each of the basecases doesn't exit that instance of the function. So when n=0 and sum<>0, SubSum is set equal to False and the function continues to the next if statement. The dataset I'm using is small and efficiency isn't an issue, I'm just trying to understand VBA's syntax.
After doing some research I found this post:Subset sum algorithm in vba
But it doesn't implement it recursively.
or use elseif to avoid exit function
Sub test()
Dim arr() As Variant
Dim sum As Long
Dim n As Long
Dim result As Boolean
arr = Array(3, 34, 4, 12, 5, 2)
n = 9
result = SubSum(arr, UBound(arr), n)
End Sub
Function SubSum(source As Variant, n As Long, sum As Long) As Boolean
If sum = 0 Then
SubSum = True
ElseIf (n = 0 And sum <> 0) Then
SubSum = False
ElseIf source(n - 1) > sum Then
SubSum = SubSum(source, n - 1, sum)
Else
SubSum = (SubSum(source, n - 1, sum) Or SubSum(source, n - 1, sum - source(n - 1)))
End If
End Function
My issue is ..... and the function continues to the next if statement.
To solve that problem you will have to use Exit Function.
For example
'
'~~> Rest of the code
'
If sum = 0 Then
SubSum = True
Exit Function
ElseIf (n = 0 And sum <> 0) Then
SubSum = False
Exit Function
End If
'
'~~> Rest of the code
'
Given inputs 1-32 how can I generate the below output?
in. out
1
1
1
1
2
2
2
2
1
1
1
1
2
2
2
2
...
Edit Not Homework.. just lack of sleep.
I am working in C#, but I was looking for a language agnostic algorithm.
Edit 2 To provide a bit more background... I have an array of 32 items that represents a two dimensional checkerboard. I needed the last part of this algorithm to convert between the vector and the graph, where the index aligns on the black squares on the checkerboard.
Final Code:
--Index;
int row = Index >> 2;
int col = 2 * Index - (((Index & 0x04) >> 2 == 1) ? 2 : 1);
Assuming that you can use bitwise operators you can check what the numbers with same output have in common, in this case I preferred using input 0-31 because it's simpler (you can just subtract 1 to actual values)
What you have?
0x0000 -> 1
0x0001 -> 1
0x0010 -> 1
0x0011 -> 1
0x0100 -> 2
0x0101 -> 2
0x0110 -> 2
0x0111 -> 2
0x1000 -> 1
0x1001 -> 1
0x1010 -> 1
0x1011 -> 1
0x1100 -> 2
...
It's quite easy if you notice that third bit is always 0 when output should be 1 and viceversa it's always 1 when output should be 2
so:
char codify(char input)
{
return ((((input-1)&0x04)>>2 == 1)?(2):(1));
}
EDIT
As suggested by comment it should work also with
char codify(char input)
{
return ((input-1 & 0x04)?(2):(1));
}
because in some languages (like C) 0 will evaluate to false and any other value to true. I'm not sure if it works in C# too because I've never programmed in that language. Of course this is not a language-agnostic answer but it's more C-elegant!
in C:
char output = "11112222"[input-1 & 7];
or
char output = (input-1 >> 2 & 1) + '1';
or after an idea of FogleBird:
char output = input - 1 & 4 ? '2' : '1';
or after an idea of Steve Jessop:
char output = '2' - (0x1e1e1e1e >> input & 1);
or
char output = "12"[input-1>>2&1];
C operator precedence is evil. Do use my code as bad examples :-)
You could use a combination of integer division and modulo 2 (even-odd): There are blocks of four, and the 1st, 3rd, 5th block and so on should result in 1, the 2nd, 4th, 6th and so on in 2.
s := ((n-1) div 4) mod 2;
return s + 1;
div is supposed to be integer division.
EDIT: Turned first mod into a div, of course
Just for laughs, here's a technique that maps inputs 1..32 to two possible outputs, in any arbitrary way known at compile time:
// binary 1111 0000 1111 0000 1111 0000 1111 0000
const uint32_t lu_table = 0xF0F0F0F0;
// select 1 bit out of the table
if (((1 << (input-1)) & lu_table) == 0) {
return 1;
} else {
return 2;
}
By changing the constant, you can handle whatever pattern of outputs you want. Obviously in your case there's a pattern which means it can probably be done faster (since no shift is needed), but everyone else already did that. Also, it's more common for a lookup table to be an array, but that's not necessary here.
The accepted answer return ((((input-1)&0x04)>>2 == 1)?(2):(1)); uses a branch while I would have just written:
return 1 + ((input-1) & 0x04 ) >> 2;
Python
def f(x):
return int((x - 1) % 8 > 3) + 1
Or:
def f(x):
return 2 if (x - 1) & 4 else 1
Or:
def f(x):
return (((x - 1) & 4) >> 2) + 1
In Perl:
#!/usr/bin/perl
use strict; use warnings;
sub it {
return sub {
my ($n) = #_;
return 1 if 4 > ($n - 1) % 8;
return 2;
}
}
my $it = it();
for my $x (1 .. 32) {
printf "%2d:%d\n", $x, $it->($x);
}
Or:
sub it {
return sub {
my ($n) = #_;
use integer;
return 1 + ( (($n - 1) / 4) % 2 );
}
}
In Haskell:
vec2graph :: Int -> Char
vec2graph n = (cycle "11112222") !! (n-1)
Thats pretty straightforward:
if (input == "1") {Console.WriteLine(1)};
if (input == "2") {Console.WriteLine(1)};
if (input == "3") {Console.WriteLine(1)};
if (input == "4") {Console.WriteLine(1)};
if (input == "5") {Console.WriteLine(2)};
if (input == "6") {Console.WriteLine(2)};
if (input == "7") {Console.WriteLine(2)};
if (input == "8") {Console.WriteLine(2)};
etc...
HTH
It depends of the language you are using.
In VB.NET, you could do something like this :
for i as integer = 1 to 32
dim intAnswer as integer = 1 + (Math.Floor((i-1) / 4) mod 2)
' Do whatever you need to do with it
next
It might sound complicated, but it's only because I put it into a sigle line.
In Groovy:
def codify = { i ->
return (((((i-1)/4).intValue()) %2 ) + 1)
}
Then:
def list = 1..16
list.each {
println "${it}: ${codify(it)}"
}
char codify(char input)
{
return (((input-1) & 0x04)>>2) + 1;
}
Using Python:
output = 1
for i in range(1, 32+1):
print "%d. %d" % (i, output)
if i % 4 == 0:
output = output == 1 and 2 or 1
JavaScript
My first thought was
output = ((input - 1 & 4) >> 2) + 1;
but drhirsch's code works fine in JavaScript:
output = input - 1 & 4 ? 2 : 1;
and the ridiculous (related to FogleBird's answer):
output = -~((input - 1) % 8 > 3);
Java, using modulo operation ('%') to give the cyclic behaviour (0,1,2...7) and then a ternary if to 'round' to 1(?) or 2(:) depending on returned value.
...
public static void main(String[] args) {
for (int i=1;i<=32;i++) {
System.out.println(i+"="+ (i%8<4?1:2) );
}
Produces:
1=1 2=1 3=1 4=2 5=2 6=2 7=2 8=1 9=1
10=1 11=1 12=2 13=2 14=2 15=2 16=1
17=1 18=1 19=1 20=2 21=2 22=2 23=2
24=1 25=1 26=1 27=1 28=2 29=2 30=2
31=2 32=1
I want a function to calculate numerology.For example if i enter "XYZ" then my output should be 3 .
Here is how it became 3:
X = 24
Y = 25
Z = 26
on adding it becomes 75 which again adds up to 12 (7+5) which again adds up to 3(1+2) . Similarly whatever names i should pass,my output should be a single digit score.
Here you are:
Function Numerology(Str)
Dim sum, i, char
' Convert the string to upper case, so that 'X' = 'x'
Str = UCase(Str)
sum = 0
' For each character, ...
For i = 1 To Len(Str)
' Check if it's a letter and raise an exception otherwise
char = Mid(Str, i , 1)
If char < "A" Or char > "Z" Then Err.Raise 5 ' Invalid procedure call or argument
' Add the letter's index number to the sum
sum = sum + Asc(char) - 64
Next
' Calculate the result using the digital root formula (http://en.wikipedia.org/wiki/Digital_root)
Numerology = 1 + (sum - 1) Mod 9
End Function
In vbscript:
Function numerology(literal)
result = 0
for i = 1 to Len(literal)
'' // for each letter, take its ASCII value and substract 64,
'' so "A" becomes 1 and "Z" becomes 26
result = result + Asc(Mid(literal, i, 1)) - 64
next
'' // while result is bigger than 10, let's sum it's digits
while(result > 10)
partial = 0
for i = 1 to Len(CStr(result))
partial = partial + CInt(Mid(CStr(result), i, 1))
next
result = partial
wend
numerology = result
End Function
I have no idea what this could possible be used for but it was fun to write anyway.
Private Function CalcStupidNumber(ByVal s As String) As Integer
s = s.ToLower
If (s.Length = 1) Then 'End condition
Try
Return Integer.Parse(s)
Catch ex As Exception
Return 0
End Try
End If
'cover to Values
Dim x As Int32
Dim tot As Int32 = 0
For x = 0 To s.Length - 1 Step 1
Dim Val As Integer = ConvertToVal(s(x))
tot += Val
Next
Return CalcStupidNumber(tot.ToString())
End Function
Private Function ConvertToVal(ByVal c As Char) As Integer
If (Char.IsDigit(c)) Then
Return Integer.Parse(c)
End If
Return System.Convert.ToInt32(c) - 96 ' offest of a
End Function