Convert Array of objects to Array with only values - arrays

I have an array (obj_values) of objects
[
#<User id: 1, name: "Kostas">,
#<User id: 2, name: "Moufa">,
...
]
And I want to convert this into an Array with only the values from above objects, so it will look like:
[
1, Kostas
2, Moufa
]
I can do it like this:
obj_table = []
obj_values.each do |ext|
ext.each do |obj|
obj_table.push([obj.id, obj.name].join(","))
end
end
However with this approach I need to explicitly specify what attributes I want to push (obj.id and obj.name), is there a way to push whole data from object without the need to specify each attribute separately?

Use .attributes to get a hash of all the attributes on the model. Call .values on it to get just the values without the keys.
Using your code:
obj_table = []
obj_values.each do |ext|
ext.each do |obj|
obj_table.push(obj.attributes.values.join(","))
end
end
Though there are better ways. I suggest you look into .map and .flat_map.
obj_table = obj_values.flat_map do |ext|
ext.map do |obj|
obj.attributes.values.join(",")
end
end

Yes, you can push data without specifying it separately. to push data you have to use an object.attributes.values
an object will be your active record object.
attributes will return a hash with all attributes of that object.
so you can change your loops into a single statement like:
obj_values.flat_map {|object_value| object_value.attributes.values }

Related

How prevent Object.keys() sort?

The problem with the ECMA standard for sort of Object.keys() is known:
Object.keys() handle all keys with integer (example: 168), including integer as strings (example: "168"), as a integer. The result is, both are the same (168 === "168"), and overwrite itself.
var object = {};
object["168"] = 'x';
object[168] = 'y';
Object.keys(object); // Array [ "168" ]
object[Object.keys(object)]; // "y"
Interestingly, all keys (including pure integer keys) are returned as a string.
The ecma262 wrote about this: All keys will be handle as a integer, expect the key is a String but is not an array index.
https://tc39.es/ecma262/#sec-ordinaryownpropertykeys
That should tell us: 168 === "168". A toString() do not solve the problem.
var object = {};
object[[3].toString()] = 'z';
object[[1].toString()] = 'x';
object[[2].toString()] = 'y';
Object.keys(object);
// Array(3) [ "1", "2", "3" ]
Paradoxically, in this case, only integer apply as "enumerable" (it's ignoring array.sort(), that sort also strings with letters.).
My question about this is simple: How can i prevent the sort function in Object.keys()? I have testet the Object.defineProperties(object, 1, {value: "a", enumerable: true/false}), but that mean not realy enumerable in the case of integer or string or integer-like string. It means only should it be counted with or not. It means "counted" like omit (if it false), not "enumerabled" like ascending or descending.
A answere like that is not a good answer: Please use only letters [a-zA-Z] or leastwise a letter at the first position of keyword.
What I want: That the keys are not sorted, but output in the order in which they were entered, whether integer, string or symbol.
Disclaimer: Please solutions only in JavaScript.
Javascript Objects are unordered by their nature. If you need an ordered object-like variable I would suggest using a map.
To achieve what you're looking for with a map instead of object you'd do something like the below:
var map1 = new Map();
map1.set("123", "c");
map1.set(123, "b");
var iterator1 = map1.keys();
var myarray = [];
for (var i = 0; i < map1.size; i++) {
myarray.push(iterator1.next().value);
}
console.log(myarray);
// Array ["123", 123]
Unfortunately it's not compatible with IE and I'm not sure how else you could achieve what you need without it. A quick Google did return something about jQuery maps, though.
If you don't want to use jQuery and still need to support IE some points are below:
Is there anything stopping you using an array rather than JS object to store the data you need? This will retain the order per your requirements unlike objects. You could have an object entry in each iteration which represents the key then use a traditional foreach to obtain them as an array. I.e.
The array:
var test_array = [
{key: 123, value: 'a value here'},
{key: "123", value: 'another value here'}
];
// console.log(test_array);
Getting the keys:
var test_array_keys = [];
test_array.forEach(function(obj) { test_array_keys.push(obj['key']); } );
// console.log(test_array_keys);
Then if you needed to check whether the key exists before adding a new entry (to prevent duplicates) you could do:
function key_exists(key, array)
{
return array.indexOf(key) !== -1;
}
if(key_exists('12345', test_array_keys))
{
// won't get here, this is just for example
console.log('Key 12345 exists in array');
}
else if(key_exists('123', test_array_keys))
{
console.log('Key 123 exists in array');
}
Would that work? If not then the only other suggestion would be keeping a separate array alongside the object which tracks the keys and is updated when an entry is added or removed to/from the object.
Object Keys sorted and store in array
First Creating student Object. then sort by key in object,last keys to store in array
const student={tamil:100, english:55, sci:85,soc:57}
const sortobj =Object.fromEntries(Object.entries(student).sort())
console.log(Object.keys(sortobj))
use map instead of an object.
let map = new Map()
map.set("a", 5)
map.set("d", 6)
map.set("b", 12)
to sort the keys (for example, to update a chart data)
let newMap = new Map([...map.entries()].sort())
let keys = Array.from(newMap.keys()) // ['a','b','d']
let values = Array.from(newMap.values()) // [5,12,6]

How to push object into an array? in Angular 7

I am pushing an object into an array but cannot do it?
I'm doing it like this
this.passData = this.tribeForm.value;
var id = {"tribe_id": 1}
this.passData.push(id)
This is the value in the tribeForm
I also tried
var id = {tribe_id: 1}
and
this.passData.splice(0,0, id)
and
this.passData = Array.prototype.slice(id)
and
this.passData.concat(id)
but it all ends up with
TypeError: this.passData.push/splice/concat is not a function
The question is not that clear, But I understood you are manipulating form data, value of form data returns an Object, Not an array. Objects in JavaScript are represented as key-value pairs, (or attribute-value) pairs.
Example :
var object = {
name : "Jhon",
grade : 12,
gpa : 8.12
}
It is just a collection of key-value pairs, push(), concat() and other methods are supported only for Arrays not for Objects. You can achieve whatever you want simply by creating a new key/attribute and assigning the value to it.
this.passData = this.tribeForm.value
this.passData['tribe_id'] = 1
//or, Objects can also contain nested object
this.passData['someKey'] = {'tribe_id' : 1}
You can create an empty array and push objects to it
Example :
var exampleArray = []
exampleArray.push({'tribe_id' : 1})
Now, it works because exampleArray is an Array not JS object.
Thanks for A2A
First, you need to understand the error:
TypeError: this.passData.push/splice/concat is not a function
Push/splice/concat is functions for Array and because of that the console is yelling at you that the passData is not an Array.
Make sure your passData is an Array and you will able to do so.

Parse Array of JSON Objects in Crystal lang

Suppose I've got a simple JSON mapped object in Crystal lang, e.g.:
class Item
JSON.mapping(
id: UInt32,
name: String,
)
end
I can parse individual objects from JSON strings easily like so:
foo = Item.from_json(%({"id":1,"name":"Foo"}))
puts "OK: foo=#{foo}"
# => OK: foo=Item(#id=1, #name="Foo")
But how would I parse an array of Items from a JSON string? I've tried a few approaches but am not sure how to proceed, e.g.:
items_str = %([{"id":1,"name":"Foo"},{"id":2,"name":"Bar"}])
items : Array(Item) = JSON.parse(items_str)
# => Error in foo.cr:15: type must be Array(Item), not JSON::Any
Of course, I'd also like to be able to do this with a JSON pull parser, so presumably there's some mapping trick or type hint I'm missing. Ideas?
Found it in this spec. So, you can use Array(Item).from_json:
items = Array(Item).from_json %([{"id":1,"name":"Foo"},{"id":2,"name":"Bar"}])
items.first.id #=> 1
items.first.name #=> "Foo"
items.last.id #=> 2
items.last.name #=> "Bar"

Json creation in ruby for a list

I am new to Ruby.
I want to create a JSON file for a group of elements.
For this, I am using eachfunction to retrieve the datas. I want to create json as follows for the 4 length array,
'{
"desc":{
"1":"1st Value",
"2":"2nd value"
"3":"3rd Value",
"4":"4th value"
},
}'
This is my array iteration,
REXML::XPath.each( doc, "//time" ) { |element1|
puts element1.get_text
}
I know here is the simple code to generate a JSON,
require 'json/add/core'
class Item < Struct.new(:id, :name); end
chair = Item.new(1, 'chair')
puts JSON.pretty_generate(chair)
This syntax will generate a json as follows,
{
"json_class": "Item",
"v": [
1,
"chair"
]
}
But I'm not sure how to do that to make JSON for my elements as stated above. Google search didn't give me a proper way to do this.
Can anyone help me here?
it means this?:
require 'json'
my_arr= ["1st Value","2nd Value","3rd Value","4th Value"]
tmp_str= {}
tmp_str["desc"] = {}
my_arr.each do |x|
tmp_str["desc"]["#{x[0]}"] = x
end
puts JSON.generate(tmp_str)
you can iterate the string array ,then take the strings to hash object.JSON can easy to parse Hash objcect .

Filter greater than and length angularjs

I need length of books that added after item, here is my controller:
$scope.items = [
{"added_days_ago": 5, "books": [{"id":1, "added_days_ago": 6}, {"id":2, "added_days_ago": 3}, {"id":3, "added_days_ago": 4}]},
{"added_days_ago": 2, "books": [{"id":4, "added_days_ago": 3}]}
]
In controller i need to define filteredBooksLength (i using ng-table) and then show like:
{{filteredBooksLength}}
Something like:
filteredBooksLength = (books where book.added_days_ago > item.added_days_ago).length
JSFiddle
$scope.filteredBooksLength = function (item) {
return item.books.filter(function (book) {
return book.added_days_ago > item.added_days_ago
}).length
Should cover your needs - summon it within the ng-repeat block, and pass in the current item - filteredBooksLength(item)
jsFiddle
How it works
We're giving the scope access to a function that accepts an item object as an argument. We take the books array on that object and pass it though a filter function, which returns only those books where book.added_days_ago is greater than item.added_days_ago as an array. We then measure the length of that array and return it.
Note on style
From what you've written - and the way you've phrased your question - it looks like you've done some Python. It's accepted practice in JS to use camelCase rather than snake_case - you may wish to change that for the the keys in your items object. In addition, the "" around those keys are superfluous.
Keep at it!

Resources