how to sort file in ruby - ruby

This is my file content.
Receivables=Por cobrar
Payables=Cuentos por pagar
ytdPurchases.label=Purchases YTD
validationError.maxValue=Value is too large, maximum value allowed is {0}
i want to sort this content in alphabetic order ...
how may i do that ??
Update:
This code will sort my file.
new_array = File.readlines("#{$base_properties}").sort
File.open("#{$base_properties}","w") do |file|
new_array.each {|n| file.puts(n)}
end
Is there a better way to sort file?

Assuming your file is called "abc"
`sort abc -o abc`
Ruby shouldn't be used as a golden hammer. By using the command sort it will be much faster.

Obvious simplification:
new_array = File.readlines("#{$base_properties}").sort
File.open("#{$base_properties}","w") do |file|
file.puts new_array
end
I'd just define a method like this, doing the opposite of File.read. It's highly reusable, and really should be part of the standard:
def File.write!(path, contents)
File.open(path, "w"){|fh| fh.write contents}
end
And then sorting becomes:
File.write!($base_properties, File.readlines($base_properties).sort.join)

File.open("out.txt", "w") do |file|
File.readlines("in.txt").sort.each do |line|
file.write(line.chomp<<"\n")
end
end

Related

Puts arrays in file using ruby

This is a part of my file:
project(':facebook-android-sdk-3-6-0').projectDir = new File('facebook-android-sdk-3-6-0/facebook-android-sdk-3.6.0/facebook')
project(':Forecast-master').projectDir = new File('forecast-master/Forecast-master/Forecast')
project(':headerListView').projectDir = new File('headerlistview/headerListView')
project(':library-sliding-menu').projectDir = new File('library-sliding-menu/library-sliding-menu')
I need to extract the names of the libs. This is my ruby function:
def GetArray
out_file = File.new("./out.txt", "w")
File.foreach("./file.txt") do |line|
l=line.scan(/project\(\'\:(.*)\'\).projectDir/)
File.open(out_file, "w") do |f|
l.each do |ch|
f.write("#{ch}\n")
end
end
puts "#{l} "
end
end
My function returns this:
[]
[["CoverFlowLibrary"]]
[["Android-RSS-Reader-Library-master"]]
[["library"]]
[["facebook-android-sdk-3-6-0"]]
[["Forecast-master"]]
My problem is that I find nothing in out_file. How can I write to a file? Otherwise, I only need to get the name of the libs in the file.
Meditate on this:
"project(':facebook-android-sdk-3-6-0').projectDir'".scan(/project\(\'\:(.*)\'\).projectDir/)
# => [["facebook-android-sdk-3-6-0"]]
When scan sees the capturing (...), it will create a sub-array. That's not what you want. The knee-jerk reaction is to flatten the resulting array of arrays but that's really just a band-aid on the code because you chose the wrong method.
Instead consider this:
"project(':facebook-android-sdk-3-6-0').projectDir'"[/':([^']+)'/, 1]
# => "facebook-android-sdk-3-6-0"
This is using String's [] method to apply a regular expression with a capture and return that captured text. No sub-arrays are created.
scan is powerful and definitely has its place, but not for this sort of "find one thing" parsing.
Regarding your code, I'd do something like this untested code:
def get_array
File.new('./out.txt', 'w') do |out_file|
File.foreach('./file.txt') do |line|
l = line[/':([^']+)'/, 1]
out_file.puts l
puts l
end
end
end
Methods in Ruby are NOT camelCase, they're snake_case. Constants, like classes, start with a capital letter and are CamelCase. Don't go all Java on us, especially if you want to write code for a living. So GetArray should be get_array. Also, don't start methods with "get_", and don't call it array; Use to_a to be idiomatic.
When building a regular expression start simple and do your best to keep it simple. It's a maintainability thing and helps to reduce insanity. /':([^']+)'/ is a lot easier to read and understand, and accomplishes the same as your much-too-complex pattern. Regular expression engines are greedy and lazy and want to do as little work as possible, which is sometimes totally evil, but once you understand what they're doing it's possible to write very small/succinct patterns to accomplish big things.
Breaking it down, it basically says "find the first ': then start capturing text until the next ', which is what you're looking for. project( can be ignored as can ).projectDir.
And actually,
/':([^']+)'/
could really be written
/:([^']+)'/
but I felt generous and looked for the leading ' too.
The problem is that you're opening the file twice: once in:
out_file = File.new("./out.txt", "w")
and then once for each line:
File.open(out_file, "w") do |f| ...
Try this instead:
def GetArray
File.open("./out.txt", "w") do |f|
File.foreach("./file.txt") do |line|
l=line.scan(/project\(\'\:(.*)\'\).projectDir/)
l.each do |ch|
f.write("#{ch}\n")
end # l.each
end # File.foreach
end # File.open
end # def GetArray

Most efficient way to iterate over hash values from two separate hash keys

I have hash value:
my_hash = {"host_names"=>["batman", "robin"], "files"=>["file1", "file2", "file3"]}
I need to iterate over each hostname, and then pull the same logs from each host.
Other than:
my_hash.each do |k, v|
k["host_names].each do |hostname|
k["log"].each do |log|
get_log_file(host, log)
end
end
end
Is there a more efficient way to do this?
Thank you in advance.
You could do it like so:
my_hash = {"host_names"=>["batman", "robin"],
"files"=>["file1", "file2", "file3"]}
def get_log_file(h,f)
puts "processing file #{f} for #{h}"
end
my_hash["host_names"].product(my_hash["files"]).each {|h,f| get_log_file(h, f)}
#=> processing file file1 for batman
# processing file file2 for batman
# processing file file3 for batman
# processing file file1 for robin
# processing file file2 for robin
# processing file file3 for robin
Well, for starters, you can get rid of the outer loop:
my_hash['host_names'].each do |host|
my_hash['files'].each do |file|
get_log_file(host, file)
end
end
It's not any more efficient really, but a little cleaner. I think this is going to be two loops no matter what.
I don't see why you're trying to iterate over the hash's keys and then call ["something"] on each of those keys. That seems wrong.
hostnames = my_hash["host_names"]
files = my_hash["files"]
hostnames.each do |hostname|
files.each do |file|
get_log_file host, file
end
end

How can I read a word list in chunks of 100?

I want to read words in chunk of 100 from a file and then process them.
I can do it adding additional counter etc, but is there a in-build command in one of the IO libs that does this. I wasnt able to find it
require 'pp'
arr = []
i = 0
f=File.open("/home/pboob/Features/KB/178/synthetic/dataCreation/uniqEnglish.out").each(" ") { |word|
i=i+1
arr << word
if i==100
pp arr
arr.clear
i=0
end
}
pp arr
Thanks!
P.S:
The file is too big to fit in memory, so I will have to use ".each "
The file is too big to fit in memory, so I will have to use ".each "
Better than each, laziness with enumerable-lazy:
require 'enumerable/lazy'
result = open('/tmp/foo').lines.lazy.map(&:chomp).each_slice(100).map do |group_of_words|
# f(groups_of words)
end
More on functional programming and laziness here.
Actually, I believe the implementation of "each_slice" is sufficiently lazy for your purposes. Try this:
open('tmp/foo').lines.each_slice(100) do |lines|
lines = lines.collect &:chomp # optional
# do something with lines
end
Not as elegant as tokland's solution but it avoids adding an extra dependency to your app, which is always nice.
I think this might be useful to you:
http://blog.davidegrayson.com/2012/03/ruby-enumerable-module.html
Assuming one word per line, and the ability to slurp an entire file into memory:
IO.readlines('/tmp/foo').map(&:chomp).each_slice(100).to_a
If you are memory-constrained, then you can interate in chunks by specifying only the chunk size; no counter required!
File.open('/tmp/foo') do |f|
chunk = []
f.each do |line|
chunk.push(line)
next unless f.eof? or chunk.size == 100
puts chunk.inspect
chunk.clear
end
end
That's pretty verbose, though it does make it clear what's going on with the chunking. If you don't mind being less explicit, you can still use slicing with an Enumerator:
File.open('/tmp/foo').lines.map(&:chomp).each_slice(100) {|words| p words}
and replace the block with whatever processing you want to perform on each chunk.
Maybe it's more straightforward to do:
File.open(filename) do |file|
do_things(100.times.map{file.gets ' '}) until file.eof?
end

puts matches from to files

I have mac addresses in mac1.txt and mac2.txt and I wanted to do something like this:
v = File.open("/RubyDev/sort/mac1.txt",'r').each_line do |a|
w = File.open("/RubyDev/sort/mac2.txt",'r').each_line do |b|
if w in v
puts w
end
end
end
Thanks in advance for your assistance!
EDIT: That first version below is actually pretty terrible. Here's a better version:
lines = []
File.open("mac1.txt",'r').each_line do |a|
lines.push(a.rstrip!)
end
File.open("mac2.txt",'r').each_line do |b|
if lines.include?(b.rstrip!)
puts b
end
end
I think what you're looking for is something like this:
File.open("mac1.txt",'r').each_line do |a|
File.open("mac2.txt",'r').each_line do |b|
if a == b
puts b
end
end
end
Is that correct? If not, could you give more background about the issue and what you're trying to accomplish?
To get all the common lines between two files, you can use File#readlines to access all the lines in the file as an array. Keep in mind that they will still have newlines ("\n") appended, so you'll need to remove them with String#chomp. The easiest way to do this is to map the array that readlines gives you, like this:
common_macs = File.open("mac1.txt").readlines.map(&:chomp) &
File.open("mac2.txt").readlines.map(&:chomp)
I am still trying to learn Ruby, so this is unlikely a good solution, but it is a possibility. It reads the contents of the first file into a hash and then checks the contents of the second against it. I think it would be reasonably efficient (well ... unless the first file is too big to fit nicely in memory).
lines = Hash.new
File.open( "mac1.txt", 'r' ).each_line do |l|
lines[l] = true
end
File.open( "mac2.txt", 'r' ).each_line do |l|
if ( lines[l] == true )
puts l
end
end
Edit For completeness, here is the very succinct version as suggested in the comments by Mark Thomas with the white space removal suggested by Gavin Anderegg. Ruby is a sweet language.
lines = Hash.new
File.open( "mac1.txt", 'r' ).each_line {|l| lines[l.strip!] = true}
File.open( "mac2.txt", 'r' ).each_line {|l| puts l if lines[l.strip!]}
lines = {}
File.open("mac1.txt").each_line {|l| lines[l.chomp] = true}
File.open("mac2.txt").each_line {|l| puts l if lines[l.chomp]}

Opening/using a table up in Ruby

I have a simple tab-separated text file that I want Ruby to read every value in the second column and write out a text file with each table value and another number. I was wondering how might I go about doing this (probably using some kind of loop).
Thanks
File.open("output.txt", "w") do |output_file|
File.open("input.txt") do |input_file|
input_file.each_line do |line|
values = line.split("\t")
output_file.puts "#{values[1]} anothervalue"
end
end
end

Resources