ruby split initial file contents into array - arrays

I have a file that I am reading that follows the following format:
12345,500,500
23456,100,150
34567,99,109
What I'm trying to do is read up until the first comma of the file and then map them into an array.
test = File.read('results.txt').split(',')[0]
p test
=> "12345"
would return me back the first value before the comma but I want to put all of them into an array
test = File.read('results.txt').split(',')[0].map(&:strip)
I have tried the following above and other similar permutations but unfortunately it's not quite the right it seems.
my desired result is to have an array of the following
[12345,23456,34567]

Here are a couple of ways to do that. First create the file.
txt =<<_
12345,500,500
23456,100,150
34567,99,109")
_
FName = "tmp"
File.write(FName, txt)
#=> 43
#1
File.foreach(FName).map { |line| line[0, line.index(',')] }
#=> ["12345", "23456", "34567"]
#2
File.foreach(FName).map { |line| line.to_i.to_s }
#=> ["12345", "23456", "34567"]
IO#foreach reads the file line-by-line, as contrasted by IO#readlines, which "gulps" the entire file into an array. foreach is therefore less demanding of memory than readlines. You can write either IO.foreach... or File.foreach... as File is a subclass of IO (File < IO #=> true).

File.readlines('results.txt').map { |line| line.split(',') }.map(&:first)
=> ["12345", "23456", "34567"]

Related

Print elements of ruby array line by line after splitting a single string with "\n" condition

I have a single string, achieved using backticks of the following form:
output = `git log`
then, I have splitted the result where there are "\n" and the result went into an array of the form:
array = output.split("\n")
then, I am just trying to output the result in the screen, however, when I am using
array.each do |a|
puts a
end
I am getting as a result a double line of the form:
result after puts
(empty line)
result after puts etc
when my preferred result is a single line of the form:
result after puts
result afters puts etc
I tried to perform this with print, but I am getting:
result after puts result after puts etc
in a single line.
Can you please help me?
The issue is when you split using \n, if there are two \n characters then an empty "" gets added to the array.
eg: test = ["this","","is","test"]
Now if you do,
test.each do |a|
puts a
end
The o/p will be,
this
// a new line will come here.
is
test
so you should reject the empty values,
test2 = test.reject{ |value| value == ""}
test2.each do |a|
puts a
end
Result is,
this
is
test
In same way,
output = `git log`
array = output.split("\n")
array2 = array.reject{ |value| value == ""}
array2.each do |a|
puts a
end
This will give you the correct result.
Thanks to #AndreyDeineko, we have that:
"The issue is when you split using \n if there are two \n characters then an empty "" gets added to the array. Howcome? a = "1\n2\n3\n4\n"; a.split("\n") #=> ["1", "2", "3", "4"].
Therefore, array.each { |a| a } will work for you"
It did not work 100% for me, but using his answer, I manage to achieve the required result which is:
array.each { |a| a }
puts array

Adding items to a new array with index

Trying to make a method skip_animals that takes an animals array and a skip integer and returns an array of all elements except first skip number of items.
input: skip_animals(['leopard', 'bear', 'fox', 'wolf'], 2)
expected output: ["2:fox", "3:wolf"]
def skip_animals(animals, skip)
arr = Array.new
animals.each_with_index{|animal, index| arr.push("#{animal}:#{index}") }
puts arr.drop(skip)
end
This instead puts each output on a separate line and doesn't add them to the array arr. I thought the arr.push would add them correctly. What do I have to do to get the elements added to the array?
I want to use these methods, not map or something more advanced. I need to tinker with this each_with_index line, not overhaul it.
(This is a challenge on Hackerrank, so it uses STDIN and STDOUT)
EDIT
Here is my updated code with p instead of puts. It's giving me a weird output of two different arrays, not sure why.
def skip_animals(animals, skip)
arr = Array.new
animals.each_with_index{|animal, index| arr.push("#{index}:#{animal}") }
p arr.drop(skip)
end
This gives me two lines of output:
["3:panda", "4:tiger", "5:deer"]
["0:leopard", "1:bear", "2:fox", "3:wolf", "4:dog", "5:cat"]
I'm assuming the top is the correct array, but I don't get why the second is printing also, or why it has a different set of animals.
Use p instead of puts.
irb(main):001:0> puts ['1', '2']
1
2
=> nil
irb(main):002:0> p ['1', '2']
["1", "2"]
According to the documentation, puts:
Writes the given objects to ios as with IO#print. Writes a record
separator (typically a newline) after any that do not already end with
a newline sequence. If called with an array argument, writes each
element on a new line. If called without arguments, outputs a single
record separator.
BTW, I would code like this (using Enumerable#map + returning result instead of printing inside the function):
def skip_animals(animals, skip)
animals.drop(skip).each_with_index.map { |animal, index|
("#{index + skip}:#{animal}")
}
end
p skip_animals(['leopard', 'bear', 'fox', 'wolf'], 2)
just remove puts remove form this line puts arr.drop(skip)
def skip_animals(animals, skip)
arr = Array.new
animals.each_with_index{|animal, index| arr.push("#{animal}:#{index}") }
arr.drop(skip)
end

Using arrays in regular expressions?

Does anyone know if there is a way to use an array in a regular expression? suppose I want to find out if somefile.txt contains one of an array's elements. Obviously the code below doesn't work, but is there something similar that does work?
array = [thing1 thing2 thing3]
file = File.open("somefile.txt")
file.each_do |line|
if /array/.match(line)
puts line
end
Basically I've got a file that contains a list of words that I need to use as search terms in another large file, and I'd like to avoid something like this:
($somefile =~ /(thing1|thing2|thing3)/)
You can use Regexp.union, it returns a Regexp that matches any of the given regex. The argument patterns could be either String or Regexp:
Regexp.union(%w(thing1 thing2 thing3))
#=> /thing1|thing2|thing3/
or
Regexp.union(/thing1/, /thing2/, /thing3/)
#=> /(?-mix:thing1)|(?-mix:thing2)|(?-mix:thing3)/
Use:
x = ['qwe', 'asd', 'zxc']
file = File.open("somefile.txt")
regexp = /(#{x.join '|'})/
file.each_do |line|
puts line if regexp.match(line)
end

Extract the contents from CSV into an array

I have a CSV file with contents:
John,1,2,4,67,100,41,234
Maria,45,23,67,68,300,250
I need to read this content and separate these data into two sections:
1.a Legend1 = John
1.b Legend2 = Maria
2.a Data_array1 = [1,2,4,67,100,41,234]
2.b Data_array2 = [45,23,67,a,67,300,250]
Here is my code; it reads the contents and separates the contents from ','.
testsample = CSV.read('samples/linechart.csv')
CSV.foreach('samples/linechart.csv') do |row|
puts row
end
Its output results in a class of array elements. I am stuck in pursuing it further.
I would recommend not using CSV.read for this it's too simple for that - instead, use File.open and read each line and treat it as a big string.
eg:
# this turns the file into an array of lines
# eg you now have: ["John,1,2,4,67,100,41,234", "Maria,45,23,67,a,67,300,250"]
lines = File.readlines('samples/linechart.csv')
# if you want to do this for each line, just iterate over this array:
lines.each do |line|
# now split each line by the commas to turn it into an array of strings
# eg you have: ["john","1","2","4","67","100","41","234"]
values = line.split(',')
# now, grab the first one as you name and the rest of them as an array of strings
legend = values[0] # "john"
data_array = values[1..-1] # ["1","2","4","67","100","41","234"]
# now do what you need to do with the name/numbers eg
puts "#{legend}: [#{data_array.join(',')}]"
# if you want the second array to be actual numbers instead of strings, you can convert them to numbers using to_i (or to_f if you want floats instead of integers)
# the following says "take each value and call to_i on it and return the set of new values"
data_array = data_array.map(&:to_i)
end # end of iterating over the array
First get the data out of csv like:
require 'csv'
csv_text = File.read('/tmp/a.csv')
csv = CSV.parse(csv_text)
# => [["John", "1", "2", "4", "67", "100", "41", "234"], ["Maria", "45", "23", "67", "a", "67", "300", "250"]]
Now you can format output as per your requirements. Eg:
csv.each.with_index(1){ |a, i|
puts "Legend#{i.to_s} = #{a[0]}"
}
# Legend1 = John
# Legend2 = Maria
You may looking for this,
csv = CSV.new(body)
csv.to_a
You can have a look at http://technicalpickles.com/posts/parsing-csv-with-ruby/
Reference this, too, if needed.
Over-engineered version ;)
class Lines
class Line
attr_reader :legend, :array
def initialize(line)
#line = line
parse
end
private
def parse
#legend, *array = #line.strip.split(",")
#array = array.map(&:to_i)
end
end
def self.parse(file_name)
File.readlines(file_name).map do |line|
Line.new(line)
end
end
end
Lines.parse("file_name.csv").each do |o|
p o.legend
p o.array
puts
end
# Result:
#
# "John"
# [1, 2, 4, 67, 100, 41, 234]
#
# "Maria"
# [45, 23, 67, 68, 300, 250]
Notes:
Basically, Lines.parse("file_name.csv") will give you an array of objects that will respond to the methods: legend and array; which holds the name and array of numbers respectively.
Jokes aside, I think OO will help maintainability.

Why does my array read from file contain bytes

I'm writing a little system that parses lines of data in a txt separated by commas,
so to be basic about it I read the file lines into an array, then use .each on the array and split everything by "'" then push it into the holding array which is returned as the database made from the file, I have made two, the first works fine but its data is stored line by line with a keyword, this one works fine, access and return all good.
I'm using a file containing text data like this
476,TACKLE,40,25,30,0,0,1,A3F,move description string with, punctuation and t's
477,ANOTHERATTACK,BLAHBLAHBLAH,1,2,3,4
This would be data parsing kind of right, well
so I go:
$fs = File_SYstem.new
#path = Dir.getwd.to_S + "/desktop/file.txt"
#data_lines = $fs.file_read_lines(#path)
#data = []
#data_lines.each do |line|
#data >> line.split(',')
end
return #data
#this would make an array of the lines, each line being an array of its elements, right?
#data = The_Code_Above_In_A_Class.new(#path)
=>#data
#data[0]
=>"354,FISSURE,10,40,50,blah blah blah, the second half of the text."
#hmmmm
#data[0][0]
=>"354"
So it seems to work fine, but some times, the numbers at the beginning come back as bytes :O
And for example:
#data.each do |line|
puts line[1].to_S #return second element which is name of move
end
This would print a list of the expected names, fine and dandy, but then I get the remaining data I didn't ask for returned below it in an unrecognizable pattern.
Maybe I can do this?
array = [1,2,3]
array = [array,array,array]
array[2][0] = "Hello!"
array.each do |item|
puts item[2]
end
=>"3"
"3"
"Hello!"
=>:
Seems to me this should work since I'm already using close variations of this style somewhere else with success.
Now this is a sample of the real 580 line file:
1,MEGAHORN,Megahorn,000,120,BUG,Physical,85,10,0,00,0,abef,Cool,"Using its tough and impressive horn, the user rams into the target with no letup."
2,ATTACKORDER,Attack Order,000,90,BUG,Physical,100,15,0,00,0,befh,Smart,The user calls out its underlings to pummel the target. Critical hits land more easily.
3,BUGBUZZ,Bug Buzz,046,90,BUG,Special,100,10,10,00,0,bek,Cute,The user vibrates its wings to generate a damaging sound wave. It may also lower the target's Sp. Def stat.
Now this is the class I use to load it up:
class Move_Data_Extracter
def initialize(path)
load $path.to_s + "/source/string_helper.rb"
#load "/mnt/sdcard/pokemon/system/source/string_helper.rb"
#path = path.to_s
#file_lines = $file_system.file_read_lines(#path.to_s)
$movedata = []
#file_lines.each do |line|
$movedata << line.split(",")
end
end
def get_move_id(move_name)
$movedata.each do |move|
if move[1].upcase.to_s == move_name.upcase.to_s
return move[0].to_i
else
return "Move Doesnt Exist In The System!"
end
end
end
end
This is the feedback I got when I accessing the first item in the returned array(s?):
irb(main):002:0> $movedata[0]
=> ["\xEF\xBB\xBF1", "MEGAHORN", "Megahorn", "000", "120", "BUG", "Physical", "8
5", "10", "0", "00", "0", "abef", "Cool", "\"Using its tough and impressive horn
", " the user rams into the target with no letup.\"\n"]
irb(main):003:0> $movedata[0][0]
=> "\xEF\xBB\xBF1"
irb(main):004:0>
Access worked ok this time but the first element is bytes and that each method I'm trying is going so wrong.
Can anyone figure out whats wrong here?
First thing, that's obviously not the code you're using as things like to_S aren't part of ruby and would instantly fail anyway.
Let's clean up the code a bit:
# $fs = File_SYstem.new # this is just not needed
path = File.expand_path "/desktop/file.txt" # instance variables *only* within explicit objects
data_lines = File.read( path ).split ","
I've no idea what the rest of what you've written really means.
This outputs:
# => ["476", "TACKLE", "40", "25", "30", "0", "0", "1", "A3F", "move description string with", " punctuation and t's\n477", "ANOTHERATTACK", "BLAHBLAHBLAH", "1", "2", "3", "4"]
This bit of code - what is it?
array = [1,2,3]
array = [array,array,array] # pure craziness!
array[2][0] = "Hello!"
array.each do |item|
puts item[2]
end
=>"3"
"3"
"Hello!"
=>:
As to why you're getting back bytes, it's because the file is (likely) encoded as UTF-8. Try File.read( path, "r:UTF-8") to get Ruby to use the correct encoding.

Resources