How to find class instances by contents of attr array? - arrays

class Dresser
##all = []
attr_accessor :name, :height, :length, :width, :contents
def initialize (name, height,length, width)
#name = name
#height = height
#length = length
#width = width
#contents = []
##all << self
end
def Dresser.all
##all
end
def add_content(content)
#contents << content
end
end
a = Dresser.new('a', 4, 6, 8)
a.add_content('sock')
a.add_content('hat')
b = Dresser.new('b', 3, 6, 9)
b.add_content('bra')
c = Dresser.new('c', 4, 7, 6)
c.add_content('hat')
How would I go about searching through ##all for the name of dressers that contain a specific item, say a hat?
Edit: Realized the code I initially entered was incorrect. Whoops!

Add a reader contents method then call select.
class Dresser
#rest of your code
def contents
#contents
end
end
#Assuming your instance additions
Dresser.all.select {|d| d.contents.include? 'hat'}
=>
[#<Dresser:0x000000020b0890 #name="a", #height=4, #length=6, #width=8, #contents=["sock", "hat"]>,
#<Dresser:0x000000020b0728 #name="c", #height=4, #length=7, #width=6, #contents=["hat"]>]

Related

How many character number does SynthText in the Wild Dataset have?

I downloaded SynthText in the Wild Dataset from official.
And then, I read official's readme.txt, however I couldn't find how many characters the dataset has.
I googled it but couldn't find it...
As you can see below example image, some symbols such like .,: and - exists. So, this dataset has alphabets(27) + numbers(10) + some symbols(?).
Does anyone know it?
I implemented own code counting up symbols.
def get_characters(basedir, imagedirname='SynthText', skip_missing=False):
class Symbols:
def __init__(self):
self.symbols = set()
def update(self, data):
self.symbols = self.symbols.union(data)
def __len__(self):
return len(self.symbols)
def __str__(self):
return ''.join(self.symbols)
symbols = Symbols()
def csvgenerator(annodir, imagedir, cbb, wBB, imname, txts, symbols, **kwargs):
image_num = kwargs.get('image_num')
i = kwargs.get('i')
imgpath = os.path.join(imagedir, imname)
img = cv2.imread(imgpath)
h, w, _ = img.shape
if not os.path.exists(imgpath):
if not skip_missing:
raise FileNotFoundError('{} was not found'.format(imgpath))
else:
logging.warning('Missing image: {}'.format(imgpath))
raise _Skip()
# convert txts to list of str
# I don't know why txts is
# ['Lines:\nI lost\nKevin ', 'will ', 'line\nand ',
# 'and\nthe ', '(and ', 'the\nout ',
# 'you ', "don't\n pkg "]
# there is strange blank and the length of txts is different from the one of wBB
txts = ' '.join(txts.tolist()).split()
text_num = len(txts)
if wBB.ndim == 2:
# convert shape=(2, 4,) to (2, 4, 1)
wBB = np.expand_dims(wBB, 2)
assert text_num == wBB.shape[2], 'The length of text and wordBB must be same, but got {} and {}'.format(
text_num, wBB.shape[2])
# replace non-alphanumeric characters with *
alltexts_asterisk = ''.join([re.sub(r'[^A-Za-z0-9]', '*', text) for text in txts])
assert len(alltexts_asterisk) == cbb.shape[
2], 'The length of characters and cbb must be same, but got {} and {}'.format(
len(alltexts_asterisk), cbb.shape[2])
for b in range(text_num):
text = txts[b]
symboltext = re.sub(r'[A-Za-z0-9]+', '', text)
symbols.update(symboltext)
sys.stdout.write('\r{}, and number is {}...{:0.1f}% ({}/{})'.format(symbols, len(symbols), 100 * (float(i + 1) / image_num), i + 1, image_num))
sys.stdout.flush()
_gtmatRecognizer(csvgenerator, basedir, imagedirname, customLog=True, symbols=symbols)
print()
print('symbols are {}, and number is {}'.format(symbols, len(symbols)))
def _gtmatRecognizer(generator, basedir, imagedirname='SynthText', customLog=False, **kwargs):
"""
convert gt.mat to https://github.com/MhLiao/TextBoxes_plusplus/blob/master/data/example.xml
<annotation>
<folder>train_images</folder>
<filename>img_10.jpg</filename>
<size>
<width>1280</width>
<height>720</height>
<depth>3</depth>
</size>
<object>
<difficult>1</difficult>
<content>###</content>
<name>text</name>
<bndbox>
<x1>1011</x1>
<y1>157</y1>
<x2>1079</x2>
<y2>160</y2>
<x3>1076</x3>
<y3>173</y3>
<x4>1011</x4>
<y4>170</y4>
<xmin>1011</xmin>
<ymin>157</ymin>
<xmax>1079</xmax>
<ymax>173</ymax>
</bndbox>
</object>
.
.
.
</annotation>
:param basedir: str, directory path under \'SynthText\'(, \'licence.txt\')
:param imagedirname: (Optional) str, image directory name including \'gt.mat\
:return:
"""
logging.basicConfig(level=logging.INFO)
imagedir = os.path.join(basedir, imagedirname)
gtpath = os.path.join(imagedir, 'gt.mat')
annodir = os.path.join(basedir, 'Annotations')
if not os.path.exists(gtpath):
raise FileNotFoundError('{} was not found'.format(gtpath))
if not os.path.exists(annodir):
# create Annotations directory
os.mkdir(annodir)
"""
ref: http://www.robots.ox.ac.uk/~vgg/data/scenetext/readme.txt
gts = dict;
__header__: bytes
__version__: str
__globals__: list
charBB: object ndarray, shape = (1, image num).
Character level bounding box. shape = (2=(x,y), 4=(top left,...: clockwise), BBox word num)
wordBB: object ndarray, shape = (1, image num).
Word level bounding box. shape = (2=(x,y), 4=(top left,...: clockwise), BBox char num)
imnames: object ndarray, shape = (1, image num, 1).
txt: object ndarray, shape = (i, image num).
Text. shape = (word num)
"""
logging.info('Loading {} now.\nIt may take a while.'.format(gtpath))
gts = sio.loadmat(gtpath)
logging.info('Loaded\n'.format(gtpath))
charBB = gts['charBB'][0]
wordBB = gts['wordBB'][0]
imnames = gts['imnames'][0]
texts = gts['txt'][0]
image_num = imnames.size
for i, (cbb, wBB, imname, txts) in enumerate(zip(charBB, wordBB, imnames, texts)):
imname = imname[0]
try:
generator(annodir, imagedir, cbb, wBB, imname, txts, i=i, image_num=image_num, **kwargs)
except _Skip:
pass
if not customLog:
sys.stdout.write('\rGenerating... {:0.1f}% ({}/{})'.format(100 * (float(i + 1) / image_num), i + 1, image_num))
sys.stdout.flush()
print()
logging.info('Finished!!!')
Finally, I got the symbol number.
It appears that ASCII printable characters without space.
INFO:root:Loading ~/data/text/SynthText/SynthText/gt.mat now.
It may take a while.
INFO:root:Loaded
}&|%_(],$^{+?##/-`).<=;~['>:\!"*, and number is 32...100.0% (858750/858750)
INFO:root:Finished!!!
symbols are }&|%_(],$^{+?##/-`).<=;~['>:\!"*, and number is 32

Array remains empty after elements were pushed in a method

class Player
def initialize(hp, attack, defence, gold)
#hp = hp
#attack = attack
#defence = defence
#gold = gold
#inventory = inventory
end
def inventory
#inventory = []
end
def buy(item)
if #gold >= item.price
#gold-=item.price
puts "You hand over #{item.price} gold, and get the #{item.name}."
puts "You have #{gold} gold left over."
#inventory.push([item.name,item.price,item.attack,item.defence])
puts "ITEMS IN INV: #{#inventory}" # output: ITEMS IN INV: [["Dagger", 4, 1, 0], ["Mucky Tunic", 2, 0, 2]]
else
puts "You can't afford this item."
end
end
end
player = Player.new(10,1,2,6)
puts player.inventory.inspect # output: []
The inventory.push line pushes the element to the array while it is inside the method, but when returned outside the method, the inventory array is empty. This is confusing because other variables that were changed inside that method in the same way come back as altered.
sample output when printed from inside the buy method:
ITEMS IN INV: [["Dagger", 4, 1, 0], ["Mucky Tunic", 2, 0, 2]]
output with player.inventory.inspect outside of the method:
[]
Whenever you call your inventory method:
def inventory
#inventory = []
end
... it assigns a new (empty) array to #inventory, thus overwriting any existing items.
The correct way is to either assign #inventory in initialize and just return it from within the getter:
class Player
def initialize(hp, attack, defence, gold)
#hp = hp
#attack = attack
#defence = defence
#gold = gold
#inventory = []
end
def inventory
#inventory
end
# ...
end
or to not assign it at all in initialize and use the conditional assignment operator:
class Player
def initialize(hp, attack, defence, gold)
#hp = hp
#attack = attack
#defence = defence
#gold = gold
end
def inventory
#inventory ||= []
end
# ...
end
which will assign [] to #inventory only if it was nil or false (i.e. the first time you call inventory).
A getter that just returns the corresponding instance variable (as in the former example) can also be created via attr_reader:
class Player
attr_reader :inventory
# ...
end
I figured it out 10 seconds after posting this, after messing about with it for an hour.
I needed to add inventory to def initialize, and then pass an empty array to player = Player.new(10,1,2,6) so it became player = Player.new(10,1,2,6,[]).
I still don't know why this works.

I pass an array to a ruby method I wrote but ruby sees a fixnum?

everyone, I'm a super Ruby n00b having problems getting my first Ruby program to work. I have found Q and A here on Stack Overflow that are closely related to the problem that I am having but no matter what I try, I just can't get rid of this error.
I have written two classes, Checkout and Register. Here's the full Register class:
<code>
load 'Register.rb'
class Checkout
def initialize
#register = Register.new
#itemCount = Hash['CH1', 0, 'AP1', 0, 'CF1', 0, 'MK1', 0]
##inventory = Hash['CH1', 3.11, 'AP1', 6.00, 'CF1', 11.23, 'MK1', 4.75]
##discount = Hash['CF1', ['BOGO', '#itemCount["CF1"]%2==0', -11.23, '#register.findLast("CF1")'], 'AP1', ['APPL', '#itemCount["AP1"]>=3', -1.50, '#itemCount["AP1"]==3 ? #register.findAll("AP1") : #register.findLast("AP1")'], 'MK1', ['CHMK', '#itemCount["MK1"]==1 && #itemCount["CH1"]==1', -4.75, '#register.findAll("MK1")']]
end
def scan(item)
#get price of item from inventory
price = ##inventory[item]
#add item and price to register
#register.ringUp(item, price)
#itemCount[item]+=1
#find and apply any applicable special
discountCheck = ##discount[item]
unless discountCheck == nil
nameOfDiscount = ##discount[item][0]
discountCondition = ##discount[item][1]
moneyOff = ##discount[item][2]
howToGetItemIndex = ##discount[item][3]
if(eval(discountCondition))
ind = eval(howToGetItemIndex)
if(ind.class == "Array")
#register.applyDiscount(ind, moneyOff, nameOfDiscount)
else #it's a Fixnum so we want to put it in an array first
indArray = [ind]
#register.applyDiscount(indArray, moneyOff, nameOfDiscount)
end
end
end
end
end
</code>
Here is the Register class:
<code>
class Register
def initialize
#itemsInOrderOfScan = Array.new
#itemInfoInOrderOfScan = Array.new
end
def ringUp(item, price)
#itemsInOrderOfScan.push(item)
#itemInfoInOrderOfScan.push(['', price])
end
def applyDiscount(indices, moneyOff, nameOfDiscount)
for i in 0..indices.length-1
ind = indices[i]
newInd = ind + 1
#itemsInOrderOfScan.insert(newInd, '')
#itemInfoInOrderOfScan.insert(newInd, [nameOfDiscount, moneyOff])
end
end
def findLast(item)
arr = Array.new
ind = #itemsInOrderOfScan.rindex(item)
arr.push(ind)
arr
end
def findAll(item)
indexOfFirstInstanceOfItem = #itemsInOrderOfScan.index(item)
arr = findLast(item)
indexOfLastInstanceOfItem = arr.at(0)
for i in indexOfFirstInstanceOfItem..indexOfLastInstanceOfItem
if(#itemsInOrderOfScan.at(i) == item)
arr.push(i)
end
end
arr
end
def printReceipt
puts "Item\t\t\tPrice"
puts "----\t\t\t-----"
total = 0
for i in 0..#itemsInOrderOfScan.length-1
currentItem = #itemsInOrderOfScan.at(i)
currentDiscountName = #itemInfoInOrderOfScan.at(i)[0]
currentPrice = #itemInfoInOrderOfScan.at(i)[1]
total += currentPrice
puts "#{currentItem}\t#{currentDiscountName}\t\t#{currentPrice}"
end
puts "-----------------------------------\n\t\t\t#{total}"
end
end
</code>
The way these classes should work when I try to run them is as follows: I feed Checkout various items and the two classes work together to create a receipt showing what has been purchased and any discounts that could be applied whenever I call the printReceipt method.
The test that I am using to debug looks like this:
<code>
load 'Checkout.rb'
basket = ['CH1', 'AP1', 'AP1', 'AP1', 'MK1']
co = Checkout.new
for i in 0..basket.length
puts basket.at(i)
co.scan(basket[i])
end
co.register.print()
</code>
The output when I run the test looks like this:
<code>
CH1
AP1
AP1
AP1
Register.rb:16:in `+': no implicit conversion of Fixnum into Array (TypeError)
from Register.rb:16:in `block in applyDiscount'
from Register.rb:14:in `each'
from Register.rb:14:in `applyDiscount'
from Checkout.rb:33:in `scan'
from main.rb:9:in `block in <main>'
from main.rb:7:in `each'
from main.rb:7:in `<main>'
</code>
Please help!
Thank you in advance.
you need to fix at 4 places,
In Checkout.rb, if(ind.class == "Array") is wrong comparison
use if(ind.class.to_s == "Array") or better use if(ind.instance_of? Array)
In you main.rb, use for i in 0...basket.length instead of for i in 0..basket.length because 1..2 => [1,2] but 1...3 => [1,2]
In Checkout.rb, after Class first line should be attr_accessor :register because you are access register in main.rb
In main.rb, co.register.printReceipt instead of co.register.print()
main.rb :
load 'Checkout.rb'
basket = ['CH1', 'AP1', 'AP1', 'AP1', 'MK1']
co = Checkout.new
for i in 0...basket.length
puts basket.at(i)
co.scan(basket[i])
end
co.register.printReceipt
Checkout.rb :
load 'Register.rb'
class Checkout
attr_accessor :register
def initialize
#register = Register.new
#itemCount = Hash['CH1', 0, 'AP1', 0, 'CF1', 0, 'MK1', 0]
##inventory = Hash['CH1', 3.11, 'AP1', 6.00, 'CF1', 11.23, 'MK1', 4.75]
##discount = Hash['CF1', ['BOGO', '#itemCount["CF1"]%2==0', -11.23, '#register.findLast("CF1")'], 'AP1', ['APPL', '#itemCount["AP1"]>=3', -1.50, '#itemCount["AP1"]==3 ? #register.findAll("AP1") : #register.findLast("AP1")'], 'MK1', ['CHMK', '#itemCount["MK1"]==1 && #itemCount["CH1"]==1', -4.75, '#register.findAll("MK1")']]
end
def scan(item)
#get price of item from inventory
price = ##inventory[item]
#add item and price to register
#register.ringUp(item, price)
p item
p #itemCount[item]
#itemCount[item]+=1
#find and apply any applicable special
discountCheck = ##discount[item]
unless discountCheck == nil
nameOfDiscount = ##discount[item][0]
discountCondition = ##discount[item][1]
moneyOff = ##discount[item][2]
howToGetItemIndex = ##discount[item][3]
if(eval(discountCondition))
ind = eval(howToGetItemIndex)
if(ind.class.to_s == "Array")
#register.applyDiscount(ind, moneyOff, nameOfDiscount)
else #it's a Fixnum so we want to put it in an array first
indArray = [ind]
#register.applyDiscount(indArray, moneyOff, nameOfDiscount)
end
end
end
end
end

How to convert a 2D array to a value object in ruby

I have a 2D array:
a = [["john doe", "01/03/2017", "01/04/2017", "event"], ["jane doe", "01/05/2017", "01/06/2017", "event"]...]
I would like to convert it to a value object in ruby. I found how to do it with a hash Ruby / Replace value in array of hash in the second answer of this question but not a 2D array. I would like to assign the value at a[0][0] to an attribute named "name", a[0][1] to "date1", a[0][2] to "date2" and a[0][3] to "event".
This is something like what I'd like to accomplish although it is not complete and I dont know how to assign multiple indexes to the different attributes in one loop:
class Schedule_info
arrt_accessor :name, :date1, :date2, :event
def initialize arr
#I would like this loop to contain all 4 attr assignments
arr.each {|i| instance_variable_set(:name, i[0])}
This should be short and clean enough, without unneeded metaprogramming :
data = [["john doe", "01/03/2017", "01/04/2017", "event"],
["jane doe", "01/05/2017", "01/06/2017", "event"]]
class ScheduleInfo
attr_reader :name, :date1, :date2, :type
def initialize(*params)
#name, #date1, #date2, #type = params
end
def to_s
format('%s for %s between %s and %s', type, name, date1, date2)
end
end
p info = ScheduleInfo.new('jane', '31/03/2017', '01/04/2017', 'party')
# #<ScheduleInfo:0x00000000d854a0 #name="jane", #date1="31/03/2017", #date2="01/04/2017", #type="party">
puts info.name
# "jane"
schedule_infos = data.map{ |params| ScheduleInfo.new(*params) }
puts schedule_infos
# event for john doe between 01/03/2017 and 01/04/2017
# event for jane doe between 01/05/2017 and 01/06/2017
You can't store the key value pairs in array index. Either you need to just remember that first index of array is gonna have "name" and assign a[0][0] = "foo" or just use array of hashes for the key value functionality you want to have
2.3.0 :006 > a = []
=> []
2.3.0 :007 > hash1 = {name: "hash1name", date: "hash1date", event: "hash1event"}
=> {:name=>"hash1name", :date=>"hash1date", :event=>"hash1event"}
2.3.0 :008 > a << hash1
=> [{:name=>"hash1name", :date=>"hash1date", :event=>"hash1event"}]
2.3.0 :009 > hash2 = {name: "hash2name", date: "hash2date", event: "hash2event"}
=> {:name=>"hash2name", :date=>"hash2date", :event=>"hash2event"}
2.3.0 :010 > a << hash2
=> [{:name=>"hash1name", :date=>"hash1date", :event=>"hash1event"}, {:name=>"hash2name", :date=>"hash2date", :event=>"hash2event"}]
It sounds like you want to call the attribute accessor method that corresponds to each array value. You use send to call methods programmatically. So you need an array of the method names that corresponds to the values you have in your given array. Now, assuming the class with your attributes is called Data.
attrs = [:name, :date1, :date2, :event]
result = a.map do |e|
d = Data.new
e.each.with_index do |v, i|
d.send(attrs[i], v)
end
d
end
The value result is an array of Data objects populated from your given array.
Of course, if you control the definition of your Data object, the best things would be to give it an initialize method that takes an array of values.
Try this:
class Schedule_info
arrt_accessor :name, :date1, :date2, :event
def initialize arr
#name = []
#date1 = []
#date2 = []
#event = []
arr.each |i| do
name << i[0]
date1 << i[1]
date2 << i[2]
event << i[3]
end
end
end

Rails 4 Passing an array of keys to exclude

I am currently passing an array of keys to be excluded , using the standard * method ...
params_to_scrub = ["created_at", "encrypted_password"]
#rows << user.attributes.except(*params_to_scrub)
Is there any way to move it into the user object and call it ?
#rows << user.attributes.except(user.params_to_exclude)
# in the User AR class
def params_to_exclude
params_to_scrub = ["created_at", "encrypted_password"]
return *params_to_scrub
end
this does(t work ...
You should make it a class method by adding self:
def self.params_to_exclude
params_to_scrub = ["created_at", "encrypted_password"]
end
And call it like this:
#rows << user.attributes.except(*User.params_to_exclude)
Try this:-
#rows << user.attributes.except("created_at", "encrypted_password")

Resources