I have a .csv file holding scores. This is what it looks like:
"name",10
The .csv is parsed with this function:
func _ready():
var file = File.new()
file.open("user://scores.csv", file.READ)
while !file.eof_reached():
line = file.get_csv_line()
text = text + "%s: %s" % [line[0], line[1]] + "\n" ## Invalid get index: '1' (on base: PoolStringArray)
The file must be ending in a new line. As a result, you get two lines while reading it. The first one has what you expect ([name, 10]), the second one is empty, causing an error when you try to index it.
When I tested this, the last line does not come as an empty array, but as an array with a single empty string. Looking around, this behavior has been there for a while. However, I found no bug reports or proposals, I wonder if there is a reason, or this was just overlooked.
You can check the number of columns you got. For example, the code below would skip any lines with not enough fields for your case:
if line.size() < 2:
continue
And this code will specifically target the extra line:
if file.eof_reached() and line.size() == 1 and line[0] == "":
break
Related
I am trying to read a text file and store the data inside into structs and I am interested in finding out how to ignore the first 4 lines (text header) in the text file.
This is the text file:
text file
I am only going to need the numeric values from it (year int, month int, max double, etc.) and ignore the four text lines above them.
This is the code I use to store the values as a collection of structs:
code
You can use func dropFirst(_ n: Int) to skip initial lines:
let lines = contents.components(separatedBy: "\n")
for line in lines.dropFirst(4) {
// ...
}
dropFirst(4) returns an “array slice” with all but the first 4
elements in the lines array, which means that the element storage
is not duplicated.
If it's always 4 lines then #Martin R has a good answer, otherwise you could see if the first word can be converted to an int like
for line in filtered {
let x = line.components(separatedBy: " ")
guard let year = Int(x[0] else {
continue
}
....
I have an array called temp containing double-precision values with dimensions 240×20×10428 . I would like to write it to a text file. I tried the following:
dlmwrite(['e:\temp\', str, '.txt'], temp, 'precision', 10);
now the problem is how to add \r\n\r\n string(two enter pressed key) after each first dimension (we have 240th of this dimension) in the text file? what should I have done? I want to have this format after all:
0.324235,...(20*10428 numbers),0.4363423,\r\n\r\n,
0.5467354,...(20*10428 numbers),0.346564,...
NOTE: this array come from .nc files and I want to convert them into .txt file using this way
The handy-dandy canned routines that ship with MATLAB are actually quite limited when it comes to customizability. Whenever you have some file writing to do with a custom format, it comes in handy to know how to do it yourself:
% Open file for writing, safely
fid = fopen(fullfile('e:\temp\', str, '.txt'), 'w');
OC = onCleanup(#() any(fopen('all')==fid) && fclose(fid));
% Simply loop through all rows
for ii = 1:size(temp,1)
% Format the numbers, with comma as separator
line = sprintf('%.10f,', temp(ii,:)); % (trick to concatenate last dimension into second one)
line(end) = []; %(remove last comma)
% Print this line, adding two PC-type newlines
fprintf(fid, '%s\r\n\r\n', line);
end
% Clean up
fclose(fid);
In general I'm defining a matlab fnction which takes the name of a file containing some numbers, one per line, reads the data in, and then returns the data in an array.
function x = readdata(filename)
This function takes the name of a file contained in the
% character array "filename", read in the data from it, and then
% return the resulting numbers in the 1-dimensional array x. The
% array x can be n x 1 or 1 x n, where n is the number of numbers
% in the data file.
%
% If the data file cannot be found, this function should print a
% warning (using the disp() function) and return x as an empty
% array. If the data file can be found but is empty or contains
% only comments (lines starting with the Matlab comment indicator %),
% this function should return an empty array x with no warning
% message.
%
%
%I'm not sure how to check if a file exist (while they are in same folder).
%I tried if exist(filename,'file') but this is not working
This is what I have now:
function x = readdata(file)
fid = fopen(file);
tline = fgets(fid);
while isnumeric(tline)
disp(tline)
tline = fgets(fid)
Thanks
I would start by taking a look at the documentation that you could find here for reading in line-by-line. It even gives a sample code that you could start with:
Reading Data Line-by-Line
MATLAB provides two functions that read lines from files and store them in
string vectors: fgetl and fgets. The fgets function copies the newline
character to the output string, but fgetl does not.
The following example uses fgetl to read an entire file one line at a time.
The function litcount determines whether an input literal string (literal)
appears in each line. If it does, the function prints the entire line preceded
by the number of times the literal string appears on the line.
function y = litcount(filename, literal)
% Search for number of string matches per line.
fid = fopen(filename);
y = 0;
tline = fgetl(fid);
while ischar(tline)
matches = strfind(tline, literal);
num = length(matches);
if num > 0
y = y + num;
fprintf(1,'%d:%s\n',num,tline);
end
tline = fgetl(fid);
end
fclose(fid);
You should be able to replace what is inside the while loop with what you are looking to do.
Of note is that the fgets and fgetl functions return character arrays (strings). Thus, you'll need to first check whether the line is a comment, and then, if not, convert the string to a numeric value using something along the lines of str2double.
As for checking existence of a file, exist(filename,'file') is definitely what you want. Its documentation is found here.
You should be able to do something like:
if ~exist(filename,'file')
% Do something... I suggest the warning function, disp could be used too...
warning('The file cannot be found!')
return
end
I am trying to extract every two consecutive columns from an array, writing a .dat with every pair. The problem is that, when using write.table() it overwrites the files. When I use print() instead of write.table() it shows the correct subsets, though.
I also need the file names to show the number of the pair of columns selected (a total of 6 pairs), as well as the number of the dimension (from 1 to 5). For this I have used an easier solution such as tagging 1:30.
for(i in 0:5) {
for (j in 1:5) {
for (k in 1:30) {
filename <- paste("Component",k, ".dat", sep="")
write.table(data[,c(2*i+1,2*i+2),j],col.names=F, row.names=F, sep= " ")
}
}
}
Any hints why it does not work?
I hope my goal is understandable. Thanks a lot for your time!
Set the argument append to TRUE:
write.table(data[,c(2*i+1,2*i+2),j],
file=filename,
append=TRUE,
col.names=F,
row.names=F,
sep= " ")
also, as correctly pointed out by #Roland, you have forgotten to pass the file argument (already added in my example above).
I'm currently working on project with Haskell, and have found myself some trouble. I'm supposed to read and insert into a list each line in a "dictionary.txt" file, but I can't seem to do so. I've got this code:
main = do
let list = []
loadNums "dictionary.txt" list
loadNums location list = do
inh <- openFile location ReadMode
mainloop inh list
hClose inh
mainloop inh list = do
ineof <- hIsEOF inh
if ineof
then return ()
else do
inpStr <- hGetLine inh
inpStr:list
mainloop inh list
It is supposed to get every line (I know it does get every line, since replacing the "inpStr:list" with a "putStrLn inpStr" works correctly, displaying all lines), and insert it into a list but I get the following error:
Couldn't match expected type `IO' against inferred type `[]'
Probably because the hGetLine isn't a String, but a IO String, which I have no idea how to handle in order to obtain a proper string I can insert in my list. I have no idea how this could be solved, or what the problem is exactly, but if anyone has any idea of how to properly get every line in a file into a list, I'd appreciate it.
Thanks in advance!
Unless this is for homework or something, there's no reason to use so much effort. Reuse is lazy!
getLines = liftM lines . readFile
main = do
list <- getLines "dictionary.txt"
mapM_ putStrLn list
But as you seem to still be learning Haskell, it is important for you to understand what CesarB has written.
In the line where the error happens, Haskell is expecting "IO a", but you are giving it a []. Simplifying things a lot, on a do block on the IO monad, every line is either:
Something which returns a value of the "IO a" type; the value of the "a" type within it is discarded (so the "a" is often "()")
A <- expression, which does the same thing but instead of discarding the value of the "a" type gives it the name to the left of the <-
A let, which does nothing more than give a name to a value
In that do block, the "hGetLine inh" returns an "IO String", and the String within it is extracted and given the name inpStr. The next line, since it's neither a let or a <-, should have a type "IO a", which it doesn't (thus causing the compiler error). What you can do instead, since you already have the String, is a let:
let list' = inpStr:list
This creates a new list consisting of the String followed by the original list, and gives it the name of "list' ".
Change the following line to use "list' " instead of "list" (thus passing it the new list). That line calls (recursively) mainloop, which will read one more line, call itself, and so on. After reading the whole file, it will return something with the "IO ()" type. This "IO ()" will be returned to the do block at loadNums. Congratulations, you just created a list with the lines read from the file, in reverse order (since you were appending to the head of the list), and then did nothing to it.
If you want to do something to it, change the "return ()" to "return list"; the return will generate a value of type "IO [String]", with the list within it (return does nothing more than encapsulating the value), which you can extract at loadNums with the <- syntax.
The rest is left as an exercise to the reader.