I've got 53 variables named W1_C14_0 to W1_C14_52, and each has a value from 1 to 15. I need to find how many "spells" of each number there are in this list - i.e. how many seperate runs of 1's, 2's etc in each case. This is what I'm doing and it's working fine, but is there any way to condense it into a loop?
DO REPEAT first = W1_C14_0 to W1_C14_51 /
second = W1_C14_1 to W1_C14_52 .
DO IF (SYSMIS(first) OR first<>second) .
DO IF (second=1) .
COMPUTE W1_spells1 = W1_spells1 + 1 .
ELSE IF (second=2) .
COMPUTE W1_spells2 = W1_spells2 + 1 .
ELSE IF (second=3) .
COMPUTE W1_spells3 = W1_spells3 + 1 .
*and so on down to...
ELSE IF (second=15) .
COMPUTE W1_spells15 = W1_spells15 + 1 .
END IF.
END IF.
END REPEAT .
You can loop through the spell variables using the VECTOR command.
VECTOR W1_spells = W1_spells1 TO W1_spells15.
DO REPEAT first = W1_C14_0 to W1_C14_51 /
second = W1_C14_1 to W1_C14_52 .
DO IF (SYSMIS(first) OR first<>second).
LOOP #i=1 TO 15.
DO IF (second=#i) .
COMPUTE W1_spells(#i) = W1_spells(#i) + 1.
END IF.
END LOOP.
END IF.
END REPEAT.
Related
I try to applied loop with condition to sum up the respective row(field), the where condition should be correct but during running of the system, the program ignored the condition and sum up all rows, any suggestion to fix this problem?
SELECT * FROM LIPS INTO CORRESPONDING FIELDS OF TABLE LT_LIPS
WHERE VGBEL = LT_BCODE_I-VGBEL "getDN number
AND VGPOS = LT_BCODE_I-VGPOS. " get vgpos = 01/02/03
LOOP AT LT_BCODE_I INTO LT_BCODE_I WHERE VGBEL = LT_LIPS-VGBEL AND VGPOS = LT_LIPS-VGPOS.
SUM.
LT_BCODE_I-MENGE = LT_BCODE_I-MENGE.
ENDLOOP
.
Although you are asking about LOOP, I think the issue is more about how you use SUM.
The statement SUM can only be specified within a loop LOOP and is only respected within a AT-ENDAT control structure.
Here is an excerpt from the ABAP documentation, for "Calculation of a sum with SUM at AT LAST. All lines of the internal table are evaluated":
DATA:
BEGIN OF wa,
col TYPE i,
END OF wa,
itab LIKE TABLE OF wa WITH EMPTY KEY.
itab = VALUE #( FOR i = 1 UNTIL i > 10 ( col = i ) ).
LOOP AT itab INTO wa.
AT LAST.
SUM.
cl_demo_output=>display( wa ).
ENDAT.
ENDLOOP.
I am trying to create password Generate in ruby. At the moment all is working just got stuck at the final piece of generating the password.
I asked user if he/she would like the password to include numbers, lowercase or uppercase.
If YES, user will enter 1 and 0 for NO.
I used the code below to generate password if everything is 1. Meaning user want to include numbers, lowercase and uppercase.
if numbers == 1 && lowercase == 1 && uppercase == 1
passGen = [(0..9).to_a + ('A'..'Z').to_a + ('a'..'z').to_a].flatten.sample(10)
end
p passGen
This works 90% of the time. 10% of the time the generated password will not include say any numbers. But everything else present. I am not sure if this is because of the size or length of Array from which the password is sampled.
Anyway lets go to the main problem below
Here is the problem, I am struggling to write the code to generate password if one or more of input is 0. That's if user don't want to include numbers. Or no numbers and uppercase etc . As I can't predict what user may want or not want. I need help on this please.
Thank you.
You will need to make your input array more dynamic:
passGen = []
passGen += (0..9).to_a if numbers == 1
passGen += ('A'..'Z').to_a if uppercase == 1
passGen += ('a'..'z').to_a if lowercase == 1
passGen.sample(10).join
Now, to tackle your other issue with missing characters - this is caused as you are simply taking 10 random characters from an array. So it can just take, for example, all digits.
To tackle this you need to get one character from each generator first and then generate the remaining characters randomly and shuffle the result:
def generators(numbers:, lowercase:, uppercase:)
[
(0..9 if numbers),
('A'..'Z' if uppercase),
('a'..'z' if lowercase)
].compact.map(&:to_a)
end
def generate_password(generators:, length:, min_per_generator: 1)
chars = generators.flat_map {|g| Array.new(min_per_generator) { g.sample }}
chars += Array.new(length - chars.length) { generators.sample.sample }
chars.shuffle.join
end
gens = generators(numbers: numbers == 1, uppercase == 1, lowercase: lowercase == 1)
Array.new(10) { generate_password(generators: gens, length: 10) }
The code doesn't know it needs to include a digit/letter from every group. The sample takes random signs and since you a basically sampling 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz there is a possibility that all the signs will not be digits.
The easiest way to fix it is to check if a sign from every group is in the "password" and then replace a random sign with a sign from group that is not present.
If I were to program this I would do it like that
def random_from_range(range)
range.to_a.sample.to_s
end
def passGen(numbers, lowercase, uppercase)
result = ''
possibleSigns = []
if numbers == 1
range = (0..9)
result += random_from_range(range)
possibleSigns += range.to_a
end
if lowercase == 1
range = ('A'..'Z')
result += random_from_range(range)
possibleSigns += range.to_a
end
if uppercase == 1
range = ('a'..'z')
result += random_from_range(range)
possibleSigns += range.to_a
end
desired_lenth = 10
while result.length < desired_lenth
result += possibleSigns.sample.to_s
end
result
end
puts passGen(1,1,1)
By saying (0..9).to_a + ('A'..'Z').to_a + ('a'..'z').to_a, you're creating an Array of 10 + 26 + 26 = 62 elements, and then you pick only 10 elements out of it.
At your place I'd wrap password generation around an until block:
def generate_password_with_digits_and_caps
[(0..9).to_a + ('A'..'Z').to_a + ('a'..'z').to_a].flatten.sample(10).join
end
passGen = ''
until passGen.match(/[A-Z]/) && passGen.match(/[a-z]/) && passGen.match(/\d/)
passGen = generate_password_with_digits_and_caps
end
This could also work (closer to your snipppet):
if numbers == 1 && lowercase == 1 && uppercase == 1
passGen = ''
until passGen.match(/[A-Z]/) && passGen.match(/[a-z]/) && passGen.match(/\d/)
passGen = [(0..9).to_a + ('A'..'Z').to_a + ('a'..'z').to_a].flatten.sample(10).join
end
end
Start with something simple and stupid:
passGen = (('0'..'9').to_a.sample(1)+ ('A'..'Z').to_a.sample(1)+('a'..'z').to_a.sample(8).shuffle).join
Technically speaking, this already fulfills your requirement. From the viewpoint of aesthetics and security, the disadvantage here is that the number of upper case characters is always 8. A more elegant solution would be to find three non-zero integers which add up to 10, and can be used as the arguments for the sample call. Also, if no numbers are requested, you simply pass 0 as argument to sample.
Since this exceeds the scope of your question, and I don't even know whether you want to go so far, I don't elaborate on this here further.
In my Ruby class, I'm building a Connect Four game that my professor will run in command prompt.
It has to be done with a double array and while loops, and no break/exit/abort, loop do, classes, instance, or global variables.
My grid array is made up of 64 '.' placeholders in a nested array. I am trying to start at the bottom row of my 8x8 grid, and drop in a player's piece: 'X' or '0'.
I'm not sure how to move upward from row 8/index 7 to row 7/index 6 if the bottom row of a column has already been taken. Do I use if or case statements? Do I decrement the row? I have tried putting in if/elsif, but I got nowhere.
def print_playing_grid (playing_board)
puts "1 2 3 4 5 6 7 8"
playing_board.each do |row|
puts row.join(" ")
end
end
print_playing_grid(grid_array)
# this 'win'/while is only here for testing so the board will repeat on screen
win = false
while win == false
puts
puts "Please select a column to make your move (Player X):"
user_choice = gets.to_i
row = 7
column = user_choice - 1
while row < grid_array.size
grid_array[row][column] = 'X'
row += 1
end
puts
print_playing_grid(grid_array)
end
As it's only two conditions (cell is occupied or not) I'd be more likely to use an if rather than a case... I would use case for multiple tests as it can be a little cleaner than if and elsif.
player_token = 'X'
row = grid_array.size - 1
column = user_choice - 1
while (grid_array.size - row) <= grid_array.size
if grid_array[row][column] == '.'
grid_array[row][column] = player_token
row = -1 # (to exit the while loop)
else
row -= 1
end
end
for an example of where I'd consider using a case...
player_token = 'X'
row = grid_array.size - 1
column = user_choice - 1
dropping_a_token = true
while dropping_a_token
case
when row < 0
dropping_a_token = false
when grid_array[row][column] == '.'
grid_array[row][column] = player_token
dropping_a_token = false
else
row -= 1
end
end
I'm trying to setup a loop that prints 1000 lines in a file, but it's printing 50000 lines. It should be adding 5 to i and 2 to c but it's adding 2 to c 100 times, adding 5 to i once then adding 2 to c another 100 times.
Here's the code,
local file = io.open("output.txt", "w")
for i=60,5055,5 do
for c=0,100,2 do
file:write(" - summon tnt ~" .. c .. " ~" .. c .. " ~" .. c .. " {Fuse:" .. i .. "}\n")
end
end
file:close()
You need one cycle and inside increase your variables as you want:
--
local c = 0
for i=60,5055,5 do
if c<100 then c = c + 2 else c=0 end
-- write
end
such an idea?
Well, your inner loop wil run 50 times for each outer loop, which runs a 1000 times, so 50'000 lines is what you can expect from this code.
The math you have for the two loops works out to 50000 file-writes. The first for loop only completes every time the inner loop completes all 50 lines. So if the first loop is running 1000 times, and the inner is going 50 times, 1000 x 50 = 50000.
You could simply remove the inner loop altogether and have code to print 1000 lines to the output file.
My code:
Func myFunc()
$lag = 1300
while (1)
MouseMove(870, 189)
sleep(10)
LC(870, 189)
sleep(1200 + $lag)
LC(1010,333)
sleep(100)
RC(826,115)
sleep(50)
LC(870,212)
sleep(50)
send("{ESC}")
sleep(150)
$x = 0
$y = 0
For $i = 0 To 27 Step 1
sleep(11)
MouseClick("left", 1158 + $x ,260 + $y)
$x+=42
if ($x = 168) Then
$x = 0
$y+=36
EndIf
Next
WEnd
EndFunc
The only delay within the for loop is the sleep(11) but it takes about .5 seconds (500ms) for each iteration rather than 11ms + whatever small delay. Also, completely removing the sleep(11) part of the loop still results in an approximately 500ms delay.
Incase anyone was wondering, it's a video game macro; the first part of the while loop opens an interface and sets something up while the second part (the for loop) is suppose to click through the inventory very quickly.
The mouse cursor takes time to move. Set the speed parameter to 0 to make it move instantly
MouseClick("left", 1158 + $x ,260 + $y,1,0)