Python equivalent of PHP array_column - php

In PHP I use the array_column() function a lot as it allows me to retrieve values from a specific column inside an array returned themselves in a nice array, for example, using this array:
$users = [
[
'id' => 1,
'name' => 'Peter'
],
[
'id' => 2,
'name' => 'Paul'
],
[
'id' => 3,
'name' => 'John'
]
];
Doing array_column($users, 'name') will return:
Array
(
[0] => Peter
[1] => Paul
[2] => John
)
Since transitioning to Python I still haven't found a built in function that I can use to do the same thing on a list of dicts for example.
Does such a function exist and if not, what is the best way to achieve this?

You can use a list comprehension to extract the 'column' of interest. There is no direct Python function to my knowledge. List comprehensions are almost always faster than using map. Python List Comprehension Vs. Map
users = [
{
'id': 1,
'name': 'Peter'
},
{
'id': 2,
'name': 'Paul'
},
{
'id': 3,
'name': 'John'
}
]
>>> [(user.get('id'), user.get('name')) for user in users]
[(1, 'Peter'), (2, 'Paul'), (3, 'John')]
Or using an enumerated index location instead of the id field:
>>> [(n, user.get('name')) for n, user in enumerate(users)]
[(0, 'Peter'), (1, 'Paul'), (2, 'John')]
Or just the names...
>>> [user.get('name') for user in users]
['Peter', 'Paul', 'John']

Something like this?
arr = [
{
'id' : 1,
'name' : 'Peter'
},
{
'id' : 2,
'name' : 'Paul'
},
{
'id' : 3,
'name' : 'John'
}
]
list(map(lambda x: x["name"], arr))

Related

Extract subset of fields from within a Laravel collection

I have a Laravel collection like this (approximating using array syntax; the actual data is a Collection of objects obtained from an API response, not a local DB):
$rows = [
[
'id': 1,
'name': 'Sue',
'age': 23,
],
[
'id': 2,
'name': 'Joe',
'age': 25,
],
]
I want to extract a subset of the fields:
$subset = [];
foreach ($rows as $row) {
$subset[] = ['name' => $row['name'], 'age' => $row['age']];
}
So that I end up with:
$subset = [
[
'name': 'Sue',
'age': 23,
],
[
'name': 'Joe',
'age': 25,
],
]
What Collection method should I use to achieve that instead of the for loop?
I found this suggestion, using a higher-order message, which made some kind of sense:
$subset = $rows->map->only(['name', 'age']);
but that just gives me a Collection of null values. Expanding it into a conventional map call produced the same effect. I feel like I want some kind of multipluck, but I'm not sure what that corresponds to!
Update
It turns out that I was doing this correctly with the higher-order map->only approach. However, while the items in my collection were a kind of Model, they were not a subclass or compatible implementation of the Laravel Model class, and lacked an implementation of the only method. The author added the method, and now it works as expected.
You were close, but you don't chain map and only, and only doesn't seem to work on a Collection of nested arrays/objects.
So, for your case, use map() with a Callback:
$rows = collect([
(object)[
'id' => 1,
'name' => 'Sue',
'age' => 23,
],
(object)[
'id' => 2,
'name' => 'Joe',
'age' => 25,
]
]);
$mapped = $rows->map(function ($row) {
return ['age' => $row->age, 'name' => $row->name];
});
dd($mapped->toArray());
Output of that would be:
array:2 [▼
0 => array:2 [▼
"age" => 23
"name" => "Sue"
]
1 => array:2 [▼
"age" => 25
"name" => "Joe"
]
]
Note: If these are arrays and not objects, then you'd do $row['age'] and $row['name'] instead of $row->age and $row->name. In Laravel, Models are both, and allow either syntax.
References:
https://laravel.com/docs/9.x/collections#method-map
https://laravel.com/docs/9.x/collections#method-only
Edit:
Some alternatives. If you have a Collection of Models, then you can natively do:
$mapped = $rows->map(function ($model) {
return $model->only(['age', 'name']);
});
If you have a Collection of Collections, then you can do:
$mapped = $rows->map(function ($collection) {
return $collection->only(['age', 'name']);
});
And lastly, if you arrays or objects, you can collect() and call ->only():
$mapped = $rows->map(function ($row) {
return collect($row)->only(['age', 'name']);
});

Create array of key => value thanks to "helper" functions

I have an 2 dimensional array with this values :
[
'id' => 12,
'title' => 'the title', //and a few other key => value
],
[
'id' => 13,
'title' => 'the title 13', // and a few other key => value
],...
In the end, I need to have a multidimensional array only with id and title
[ $item['id'] => $item['title'], ...]
Usually, I'm doing a simple foreach to achieve this, but I want to use php function now. I've done this, but is there a proper way to do this?
$list = array_combine(array_column($list_forms, 'id'), array_column($list_forms, 'title'));
With third argumenf of array_column it is:
$list = array_column($list_forms, 'title', 'id');

PHP re-group array by each column to multiple array without loop

PHP re-group array by each column to multiple array without loop
In Laravel DB return, i.e. ->get()->toArray() result is as such:
[
['ts' => 1234, 'a' => 3, 'b' => 2],
['ts' => 1244, 'a' => 2, 'b' => 6],
['ts' => 1254, 'a' => 8, 'b' => 3],
]
Is there any way that I am able to transform the data to as such:
[
['column' => 'a', 'values' => [[1234, 3], [1244, 2], [1254, 8]],
['column' => 'b', 'values' => [[1234, 2], [1244, 6], [1254, 3]],
]
I just wish to know if there's any best / efficient way to render the transformation as described above. Avoid re looping again as data is already available, it can be thought as a data formatting question. Also, I do not wish to use additional array if possible.
Things that I've already looked includes ->get()->map(function()), however this is sequential and I am not able to get values in 2D array as a result.
You'll want to map over your items and return the ts value, as well as the value for each column, respectively:
$items = Model::all();
$result = [
[
'column' => 'a',
'values' => $items->map(function ($item) {
return [$item->ts, $item->a];
})
],
[
'column' => 'b',
'values' => $items->map(function ($item) {
return [$item->ts, $item->b];
})
],
];
If you want to combine the logic for both columns, create a collection of column names, and map over those:
$items = Model::all();
$result = collect(['a', 'b'])->map(function ($column) use ($items) {
$values = $items->map(function ($item) use ($column) {
return [$item->ts, $item->{$column}];
});
return compact('column', 'values');
});

Best way to convert keys in PHP

Im retrieving data from a mysql database like following Array:
$data = [
0 => [
'id' => 1,
'Benutzer' => 'foo',
'Passwort' => '123456',
'Adresse' => [
'Strasse' => 'bla', 'Ort' => 'blubb'
],
'Kommentare' => [
0 => ['Titel' => 'bar', 'Text' => 'This is great dude!'],
1 => ['Titel' => 'baz', 'Text' => 'Wow, awesome!']
]
],
]
Data like this shall be stored in a mongo database and therefore i want to replace the keynames with translated strings that come from a config- or languagefile ('Benutzer' -> 'username').
Do i really have to iterate over the array and replace the keys or is the a better way to achieve that?
If you don't want to iterate over the array then you can change the column name in the query itself using select() function.
Considering your model name is Client then your query will be:
Client::select('Benutzer as username', '...') // you can use `trnas()` function here also
->get()

JIT building a functional json for organisation chart

I want to build a json request required for JIT SpaceTree.
The workflow: a question is started with the id of the retrospective answer stored.
If the option is yes then it loads the next question based on the load_yes value. this load_yes value selects the id and loads that question.
If the option is no it loads the next no based question by its id stored under load_no,
json should look like:
var json = {
id: "start",
name: "does test work?",
data: {},
children: [{
id: "layer1_1",
name: "option: no, id 3, Q: test does work with option no?",
data: {},
children: []
}, {
id: "layer1_2",
name: "option: yes, id 2, Q: test does work!!",
data: {},
children: [{
id: "layer2_1",
name: "option: no, id 4, Q: test does work?",
data: {},
children: []
}, {
id: "layer2_2",
name: "option: yes, id 5, Q: ",
data: {},
children: []
}]
}]
};
$query = $mysqli->query("SELECT * FROM topic_answer");
while($obj = $query->fetch_object()){
$arr[] = array(
'id' => $obj->id,
'name' => $obj->topic_question,
'data' => '',
'children' => array(array(
'id' => $obj->load_yes,
'name' => $obj->load_yes,
'data' => '',
'children' =>array(),
),array(
'id' => $obj->load_no,
'name' => $obj->load_no,
'data' => '',
'children' => array(),
),
)
);
id, topic_name, topic_creator, topic_question, load_yes, start, load_no, end
1 test jordan does test work? 2 1 3 0
4 test jordan test does work no 0 0 0 0
5 test jordan test does work yes 0 0 0 0
2 test jordan test does work yes!! 4 0 5 0
in json, objects are depicted as {}. so basically what this code means is an array of objects:
[
{},
{}
]
so here, where you are nesting arrays:
'children' => array(array(
'id' => $obj->load_yes,
'name' => $obj->load_yes,
'data' => '',
'children' =>array(),
),array(
'id' => $obj->load_no,
'name' => $obj->load_no,
'data' => '',
'children' => array(),
),
)
you actually want to replace the inner array by an object, such as stdClass(). stdClass is used like this:
$obj = new stdClass();
$obj->id = "layer1_1";
$obj->name = "option: no, id 3, Q: test does work with option no?";
$obj->data = new stdClass();
$obj->children = array();
then, with php
'children' => array(
$obj1,
$obj2,
),

Categories