0

I'm trying to find out if I can delete an array with a method called on itself. array.clear removes all elements, but not the array itself.

Context

Here is the context. I have a CSV file with no headers. I want to be able to delete a row given one value in the row. So, the user can pass me "Chocolate", I seach the CSV and delete the row with Chocolate as the first value.

CSV file

Chocolate, some description blah
Cheese, some description about this one

Ruby file

require 'csv'

def remove_recipe(recipe_name)
  CSV.foreach(csv_file_path, w+) do |row|
    row.clear??? if row[0] == recipe_name
  end
end

I could add a header but I'd like to know if it's possible without.

Ok, to describe the input and output as Sawa has asked: A user will input string "Chocolate". I will search the CSV file for that string. If present, I want to update the CSV file to remove the row containing that string.

7
  • Your code does not help. Describe the input and output. Commented Oct 13, 2017 at 16:27
  • 2
    My edit undone. Do people not see that "post have been updated while you were editing" notification? :( Commented Oct 13, 2017 at 16:31
  • @SergioTulentsev sorry, I've changed it back Commented Oct 13, 2017 at 16:34
  • By the way my edit got stuck, wrapping around Sergio's edit, with edit #4 being empty. It looks like a bug on StackOverflow. Commented Oct 13, 2017 at 16:34
  • 2
    @sawa: yeah, race condition, it seems :) Commented Oct 13, 2017 at 16:35

2 Answers 2

3

Parse the CSV as an array of arrays and remove the elements you want to remove:

require "csv"

def remove_recipe(recipe_name)
  csv_ary = CSV.read("path/to/file.csv")
  cleaned_csv_ary = csv_ary.reject { |row| row[0] == recipe_name }
  # etc
end

Where I wrote "etc" you can use the cleaned array as you like, including converting it into a CSV string via #to_csv and writing it to a file.

Sign up to request clarification or add additional context in comments.

8 Comments

Another option is to use reject! to remove them from the original array.
Absolutely, @tadman. I just figured it'd be more readable to rename the var anyway.
I think the in-place modification steers closer to the intent in the original question: Deleting rows.
You can't avoid "parsing the file into an array", that's just how the CSV library works, and how Ruby works in general. You'll need to reject! and then re-write the file. Altering the array doesn't alter the source of that array, you need to explicitly write it out again.
As @tadman says, you can't just delete a row in the file and have all the following rows just "move one up" - that's not physically possible. You have to read the data into memory and flow them back down onto disk without the row in question. You could truncate the existing file to the row before the deleted row and stream the rest of the rows back out.
|
2

If you are looking to update the CSV file, then this is the cleanest solution I could come up with:

require "csv"

def remove_recipe(name)
  rows = CSV.read('test.csv')
  rows.reject! { |r| r[0] == name }
  out = rows.inject([]) { |csv, row| csv << CSV.generate_line(row) }.join("")
  File.open('test.csv', 'w+') { |file| file.write(out) }
end

remove_recipe('Chocolate')

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.