I am just starting to learn ruby and I am having troubles splitting my strings by spaces.
First I read in my file and break them up by the newline character :
inputfile = File.open("myfile.in")
filelines = inputfile.read.split("\n")
Then I try to read each of the two numbers individually:
filelines.each_with_index {|val, index| do_something(val, index)}
Where do_something is defined as:
def do_something(value, index)
if index == 0
numcases = value
puts numcases
else
value.split(" ")
puts value
puts value[0] #trying to access the first number
puts value[1] #trying to access the second number
end
end
but with a smaller input file like this one,
42
4 2
11 19
0 10
10 0
-10 0
0 -10
-76 -100
5 863
987 850
My outputs ends up looking like this:
42
4 2
4
11 19
1
1
0 10
0
10 0
1
0
-10 0
-
1
0 -10
0
-76 -100
-
7
5 863
5
987 850
9
8
so what I am understanding is that it is breaking it up character by character, rather than by spaces. I know it can read in the whole line, as I can print the contents of the array in its entirety, but I dont know what I am doing wrong.
I have also tried replacing value.split(" ") with:
value.gsub(/\s+/m, ' ').strip.split(" ")
value.split
value.split("\s")
Using RubyMine 2017.3.2
As was said in the comments, plus some other points, with an idiomatic code sample:
lines = File.readlines('myfile.in')
header_line, data_lines = lines[0], lines[1..-1]
num_cases = header_line.to_i
arrays_of_number_strings = data_lines.map(&:split)
arrays_of_numbers = arrays_of_number_strings.map do |array_of_number_strings|
array_of_number_strings.map(&:to_i)
end
puts "#{num_cases} cases in file."
arrays_of_numbers.each { |a| p a }
File.readlines is super handy!
I don't think you were calling to_i on the header information, that
will be important.
The data_lines.map(&:split) will return an array of the numbers as strings, but then you'll need to convert those strings to numbers too.
The p a in the final line will use the Array#inspect method, which is handy for viewing arrays as arrays, e.g. [12, 34].
Related
I am brand new to python and am trying to write a script that iterates over a list created by parsing a simple tab delineated file then comparing values in that list.
The input file looks like this:
1 11 12
9 46 200
471 56 30
And the code is:
with open("my_file.txt", "r") as my_file:
str = my_file.read()
clnstr = str.replace('\n', '\t')
content_list = clnstr.split("\t")
for i in range(0, len(content_list)-3, 3 ):
if (content_list[i+1] >= content_list[i]):
print(content_list[i], "is smaller than", content_list[i+1])
else :
print(content_list[i], "is bigger than", content_list[i+1])
However the output of these comparisons is wrong for some of the values:
1 is smaller than 11
9 is bigger than 46
471 is smaller than 56
I think its because its only comparing the first digits of the numbers stored in the array? If so how do i fix this in the above code?
I've got stdin like that (elements are always > 10)
75 33 44 51
51 87 33 77
77 51 91 45
17 29 30 40
I would like to substitute 1 for one of the elements in each row (randomly - according to a random 1 =< n =< 4) and 0 for the others in the row, but so as to change equal elements throughout, i.e., 51 in the 1st, 2nd, and 3rd rows, 33 in in the 1st and 2nd rows, and 77 in the 2nd and 3rd rows but so that I don't get two 1s in a row. Assuming that n=4 for the 1st and 2nd row, and n=3 for the 3rd and 4th one, I should end up with
0 0 0 1
1 0 0 0
0 1 0 0
0 0 1 0
which is different from just putting n's in, i.e., I don't want
0 0 0 1
0 0 0 1
0 0 1 0
0 0 1 0
What I actually want is to change all occurrences of equal elements according to the values of their elements throughout. E.g., replacement 51 -> 1 should change 51 in the 1st, 2nd, and 3rd row to 1 as soon as 51 in the 1st row is changed to 1, but not their names. Their names c(i,j) in the array should, however, respond with their new value when called. Then, random n's should be overruled by already existing 0's and 1's in each next row, but should stay when a row is not so affected via links to the previous rows as the 4th row.
I didn't put in any Fortran specifics because I want to avoid the discussion being led astray. Constructive suggestions would be greatly appreciated.
You need to read about the WHERE construct. If I understand your description, this toy program should work for you.
program foo
implicit none
integer c(3,4), i, n
real u
c = transpose(reshape([75,33,44,51,51,87,33,77,77,51,91,45],[4,3]))
call prn ! Print original matrix
do i = 1, 3
call random_number(u)
n = 1 + floor(4*u)
print '(A,I0)', 'n = ', n
where(c(i,:) /= c(i,n)) c(i,:) = 0
where(c == c(i,n)) c = 1
call prn ! Print altered matrix
end do
contains
subroutine prn
integer i
do i = 1, 3
write(*,'(4(I0,1X))') c(i,:)
end do
print *
end subroutine prn
end program foo
So my problem is i have a tuple with tuples inside it and i want to replace the 1 inside the tuples into # and 0 to .
Although im still to figure that one my myself when i convert the main tuple to a string i dont want the parentises and i want it displayed in columns but its not working so if someone could help me i would appreciate it a lot.
maze = ((1,1,1,1),(1,0,0,1),(1,0,0,1),(1,0,0,1),(1,1,1,1))
def tuplestr(maze):
string = ""
string += str(maze)
return string
so basically in the the result is ((1,1,1,1),(1,0,0,1),(1,0,0,1),(1,0,0,1),(1,1,1,1)) but in a string and i want this as a result
1 1 1 1
1 0 0 1
1 0 0 1
1 0 0 1
1 1 1 1
instead of this ((1,1,1,1),(1,0,0,1),(1,0,0,1),(1,0,0,1),(1,1,1,1)) string
I'm trying to write a Sudoku solver, which is the fun part. The un-fun part is actually loading the puzzles into Julia from a text file. The text file consists of a series of puzzles comprising a label line followed by 9 lines of digits (0s being used to denote blank squares). The following is a simple example of the sort of text file I am using (sudokus.txt):
Easy 7
000009001
008405670
940000032
034061800
070050020
002940360
890000056
061502700
400700000
Medium 95
000300100
800016070
000009634
001070000
760000015
000020300
592400000
030860002
007002000
Hard 143
000003700
305061000
000200004
067002100
400000003
003900580
200008000
000490308
008100000
What I want to do is strip out the label lines and store the 9x9 grids in an array. File input operations are not my specialist subject, and I've tried various methods such as read(), readcsv(), readlines() and readline(). I don't know whether there is any advantage to storing the digits as characters rather than integers, but leading zeros have to be maintained (a problem I have encountered with some input methods and with abortive attempts to use parse()).
I've come up with a solution, but I suspect it's far from optimal:
function main()
open("Text Files\\sudokus.txt") do file
grids = Vector{Matrix{Int}}()
grid = Matrix{Int}(0,9)
row_no = 0
for line in eachline(file)
if !(all(i -> isnumber(i), line))
continue
else
row_no += 1
squares = split(line, "")
row = transpose([parse(Int, square) for square in squares])
grid = vcat(grid, row)
if row_no == 9
push!(grids, grid)
grid = Matrix{Int}(0,9)
row_no = 0
end
end
end
return grids
end
end
#time main()
I initially ran into #code_warntype problems from the closure, but I seem to have solved those by moving my grids, grid and row_no variables from the main() function to the open block.
Can anyone come up with a more efficient way to achieve my objective or improve my code? Is it possible, for example, to load 10 lines at a time from the text file? I am using Julia 0.6, but solutions using 0.7 or 1.0 will also be useful going forward.
I believe your file is well-structured, by that I mean each 1,11,21... contains difficulty information and the lines between them contains the sudoku rows. Therefore if we know the number of lines then we know the number of sudokus in the file. The code utilizes this information to pre-allocate an array of exactly the size needed.
If your file is too-big then you can play with eachline instead of readlines. readlines read all the lines of the file into the RAM while eachline creates an iterable to read lines one-by-one.
function readsudoku(file_name)
lines = readlines(file_name)
sudokus = Array{Int}(undef, 9, 9, div(length(lines),10)) # the last dimension is for each sudoku
for i in 1:length(lines)
if i % 10 != 1 # if i % 10 == 1 you have difficulty line
sudokus[(i - 1) % 10, : , div(i-1, 10) + 1] .= parse.(Int, collect(lines[i])) # collect is used to create an array of `Char`s
end
end
return sudokus
end
This should run on 1.0 and 0.7 but I do not know if it runs on 0.6. Probably, you should remove undef argument in Array allocation to make it run on 0.6.
Similar to Hckr's (faster) approach, my first idea is:
s = readlines("sudoku.txt")
smat = reshape(s, 10,3)
sudokus = Dict{String, Matrix{Int}}()
for k in 1:3
sudokus[smat[1,k]] = parse.(Int, permutedims(hcat(collect.(Char, smat[2:end, k])...), (2,1)))
end
which produces
julia> sudokus
Dict{String,Array{Int64,2}} with 3 entries:
"Hard 143" => [0 0 … 0 0; 3 0 … 0 0; … ; 0 0 … 0 8; 0 0 … 0 0]
"Medium 95" => [0 0 … 0 0; 8 0 … 7 0; … ; 0 3 … 0 2; 0 0 … 0 0]
"Easy 7" => [0 0 … 0 1; 0 0 … 7 0; … ; 0 6 … 0 0; 4 0 … 0 0]
\tTrying to split this Tab delimited data set:
171 1000 21
269 1000 25
389 1000 40
1020 1-03 30 1
1058 1-03 30 1
1074 1-03 30 1
200 300 500
(for clarity: )
171\t1000\t21\t\n
269\t1000\t25\t\n
389\t1000\t40\t\n
1020\t1-03\t30\t1\n
1058\t1-03\t30\t1\n
1074\t1-03\t30\t1\n
200\t300\t\t500\n
a = text.split(/\n/)
a.each do |i|
u = i.split(/\t/)
puts u.size
end
==>
3
3
3
4
4
4
4
The \t\n combination seems to shave off the last \t, which I need for further importation. How can I get around this? Cheers
Edited: This is what I was expecting:
4
4
4
4
4
4
4
If this is for production, you should be using the CSV class as #DmitryZ pointed out in the comments. CSV processing has a surprising number of caveats and you should not do it by hand.
But let's go through it as an exercise...
The problem is split does not keep the delimiter, and it does not keep trailing null columns. You've hit both issues.
When you run a = text.split(/\n/) then the elements of a do not have newlines.
a = [
171\t1000\t21\t
269\t1000\t25\t
389\t1000\t40\t
1020\t1-03\t30\t1
1058\t1-03\t30\t1
1074\t1-03\t30\t1
200\t300\t\t500
]
Then, as documented in String#split, "if the limit parameter is omitted, trailing null fields are suppressed.", so u = i.split(/\t/) will ignore that last field unless you give it a limit.
If you know it's always going to be 4 fields, you can use 4.
u = i.split(/\t/, 4)
But it's probably more flexible to use -1 because "If [the limit is] negative, there is no limit to the number of fields returned, and trailing null fields are not suppressed." so that will keep the empty fields without hard coding the number of columns in the CSV.
u = i.split(/\t/, -1)