How to get array values from Eloquent pluck method - laravel

I have a table with two columns, X and Y and data something like:
X Y
1 1
1 2
1 3
1 4
2 5
2 6
And when I do something like ->pluck('Y', 'X') I want an answer like:
['1' => [1,2,3,4], '2' => [5,6]]
But instead it just gives me one value instead of an array like
['1' => 1, '2' => '5']
How can I make the values an array?

Using reduce
$collection->reduce(function ($carry, $item) {
// First iteration
if ($carry == null) {
$carry = [];
}
$carry[$item->X][] = $item->Y;
return $carry;
});
Using groupBy:
$collection->groupBy('X')->map(function ($item) {
return $item->pluck('Y');
})->toArray()
Using mapToGroups
$collection->mapToGroups(function ($item) {
return [$item['X'] => $item['Y']];
})->toArray()

Related

How to get last 7 days records with 0 counts

I have an eloquent query that gets the total count records (created_at) of the last 7 days. But the problem is if one of these days have 0 records, this doesn't appear in the final data.
My query:
$data = Data::whereBetween('created_at', [Carbon::now()->subDays(6)->format('Y-m-d')." 00:00:00", Carbon::now()->format('Y-m-d')." 23:59:59"])
->groupBy('date')
->orderBy('date')
->get([
DB::raw('DATE(created_at) as date'),
DB::raw('count(*) as total')
])
->pluck('total', 'date')->toArray();
What I get:
[
"2020-04-14" => 1
"2020-04-16" => 1
"2020-04-18" => 1
"2020-04-19" => 1
]
What I expected:
[
"2020-04-14" => 1
"2020-04-15" => 0
"2020-04-16" => 1
"2020-04-17" => 0
"2020-04-18" => 1
"2020-04-19" => 1
"2020-04-20" => 0
]
Any suggestions?
SOLUTION:
-Based on Gary Houbre's proposal:
$results = Data::whereBetween('created_at', [Carbon::now()->subDays(6)->format('Y-m-d')." 00:00:00", Carbon::now()->format('Y-m-d')." 23:59:59"])
->groupBy('date')
->orderBy('date')
->get([
DB::raw('DATE_FORMAT(created_at, "%Y-%m-%d") as date'),
DB::raw('count(*) as total')
])
->keyBy('date')
->map(function ($item) {
$item->date = Carbon::parse($item->date);
return $item;
});
$period = new DatePeriod(Carbon::now()->subDays(6), CarbonInterval::day(), Carbon::now()->addDay());
$graph = array_map(function ($datePeriod) use ($results) {
$date = $datePeriod->format('Y-m-d');
return $results->has($date) ? $results->get($date)->total : 0;
}, iterator_to_array($period));
Looking directly Sql : How to include "zero" / "0" results in COUNT aggregate?
Into a same table : How to get the record if Count is zero in Laravel
You need to add an outer join into your request with Eloquent.
My idea is to create a for loop to check the days.
If there is no record on a date then print 0
Loop Iteration:
Catch the first Day (Suppose 14)
Catch the last Day
Then check in every iteration it is greater than one or many
Thus, I hope you will get normally.
We had a similar problem while trying to put back-end data into the chart. Since some of the days were missing it didn't look well. Our solution was;
Create a function like this;
public function generateDates(Date $startDate, Date $endDate, $format = 'Y/m/d'): Collection
{
$dates = collect();
$startDate = $startDate->copy();
for ($date = $startDate; $date->lte($endDate); $date->addDay()) {
$dates->put($date->format($format), 0);
}
return $dates;
}
In your case it's going to be (today and today - six days) and you will union returning collection with your query collection. What it does is; it create a date range from the keys and fill them with zero. When your query collection has some value other than zero - it is going to overwrite it.

How do I output the diffence between values of Array A to Array B in Laravel?

I have an array that plucks values to an array like so:
/* Pluck just the wattage values to an array */
$realtime_data_array = $latestrtfeed->nth(60)->reverse()->pluck('data')->toArray();
which results in:
array:150 [▼
0 => 20277.6
1 => 20281.4
2 => 20285.3
3 => 20289.7
4 => 20293.8
5 => 20298.6
6 => 20303.2
7 => 20307.4
8 => 20311.5
9 => 20315.8
10 => 20319.8
these value get inputted to the chart like so:
$realtime_consumption_chart->dataset('kWh', 'line', $realtime_data_array);
The problem is that the sensor is storing cumulative values and I only want to show the difference between value 0 and value 1 then difference between value 1 and value 2 and so on and so on.
How would I go about something like that?
I am going to take a shot and say that I'm going to have to do a FOREACH on the array and create a new array with the values adjusted, but how do I go about that? maybe:
foreach ($realtime_data_array as $data) {
$realtime_data_array_corrected = ($data[1]-$data[0])->toArray();
}
Nope there is something I'm doing wrong or not considering here.
for ($i = 0; $i < sizeof($realtime_data_array); $i++) {
if($i==0) {
$realtime_data_array_corrected[$i] = 0;
continue;
}
$realtime_data_array_corrected[$i] = $realtime_data_array[$i] - $realtime_data_array[$i-1];
}

Using GroupBy and Max in LINQ Lambda Expressions

I have a collection, for example:
**id1, id2, value**
1 9 12
2 9 6
3 11 8
4 11 87
I want to use LINQ and get the following result:
**value**
6
87
P.S.
id1 - select MAX;
id2 - group column;
I need an answer in the form of
var result = list.GroupBy(x=>x.id2).select(s=>s.value);
I hope for your help.
EDIT: Okay, now we've got a slightly clearer set of requirements (though still far from clearly written) the simplest approach would probably be:
var maxes = list.GroupBy(x => x.id2,
(key, xs) => xs.OrderByDescending(x => x.id1)
.First()
.value);
Unfortunately LINQ doesn't provide a simple way of getting "the element with the maximal value" (instead of the maximal value itself). I have a method in MoreLINQ which does this though, called MaxBy:
var maxes = list.GroupBy(x => x.id2,
(key, xs) => xs.MaxBy(x => x.id2).value);
Original answer (Grouping by id2, taking the maximum value)
I'm answering assuming you actually meant to group by id2 rather than id1, and you actually wanted the results of 12 and 87 rather than 6 and 87. In that case, you'd want:
var maxes = list.GroupBy(x => x.id2, (id, xs) => xs.Max(x => x.value));
Or (possibly simpler to understand):
var maxes = list.GroupBy(x => x.id2)
.Select(xs => xs.Max(x => x.value));
Or:
var maxes = list.GroupBy(x => x.id2, x => x.value)
.Select(values => values.Max());
Or:
var maxes = list.GroupBy(x => x.id2, // Key selector
x => x.value, // Element selector
(key, values) => values.Max()); // Result selector
Or even:
var maxes = list.GroupBy(x => x.id2)
.Select(xs => xs.Select(x => x.value).Max());
As you can see, GroupBy has lots of overloads :)
Or you could use a query expression:
var maxes = from x in list
group x.value by x.id2 into values
select values.Max();
You shouldn't restrict yourself to either query expressions or the extension method version - it's important to understand both, so you can use whatever's most appropriate.
Apparently OP wants the Value with maximum Id1 within Id2:
Sample data:
public class Row
{
public int Id1;
public int Id2;
public int Value;
}
List<Row> rows = new List<Row>(){
new Row(){Id1=1,Id2=9,Value=12},
new Row(){Id1=2,Id2=9,Value=6},
new Row(){Id1=3,Id2=11,Value=8},
new Row(){Id1=4,Id2=11,Value=87}
};
Solution:
List<int> res = rows.GroupBy(r => r.Id2)
.Select(g => g.OrderByDescending(i=>i.Id1).First().Value)
.ToList();
In case it helps others, I had a similar situation except multiple records needed to be returned instead of a single record.
Eg.
**id1, id2, value**
1 9 12
2 9 6 <-
2 9 7 <-
3 11 8
4 11 87 <-
4 11 88 <-
The following returns the above four records as two lists of two records (enumerable of enumerables):
var maxes = from x in list
group x by x.id2 into xs
select new {values = xs.Where(x => x.id1 == xs.Max(y => y.id1))};
or
var maxes = list.GroupBy(x => x.id2,
(key, xs) => new
{
values = xs.Where(x => x.id1 == xs.Max(y => y.id1))
});

Reordering the linq statement after group by

Basicly, i have a statement which is like that
Contents
.Where(x=>x.CategoryId==5 && x.Status==1)
.GroupBy(q=>q.VersionId)
.OrderByDescending(q=>q.Key)
.Take(100)
.Select(q => new { VersionId = q.Key, MajorVersion = q.Max(x => x.MajorVersion) })
At the moment, it looks like below. But i want to reorder MajorVersion field as a descending...
VersionId MajorVersion
387276 2
365015 1
355427 3
369865 1
How do i do that?
Select returns an IEnumerable so you can do further sorting/ordering etc after.
Contents
.Where(x => x.CategoryId == 5 && x.Status == 1)
.GroupBy(q => q.VersionId)
.OrderByDescending(q => q.Key)
.Take(100)
.Select(q => new { VersionId = q.Key, MajorVersion = q.Max(x => x.MajorVersion) })
.OrderByDescending(x => x.MajorVersion);
Just move the OrderByDescending after the Select.
You will then be able to sort by the fields in the select. (since you'll be calling OrderByDescending on the IQueryable of anonymous types returned by Select())

Simple Math based captcha

reCaptcha is now difficult to read (decipher actually). So I am looking for an alternative captcha system to use.
I am thinking of using a simple Math based system, for example : "What is 2+5".
Are there any such plugins, or, ideas on how to build my own?
(Not complicated math like this one)
PHP - Generates a simple addition or subtraction math question, randomly alternating between displaying numbers (10 - 3) and words (seven plus five) and accepts answers numerically (14) or as words (fourteen). Returns an array representing the components of the equation
[0] - first variable value, as string, like either '4' or 'four'
[1] - second value, the operator, like '+' or 'plus'
[2] - third value, the second variable, like 'ten' or '10'
[3] - the answer, in numerical form, like '14'
[4] - the answer, in text form, like 'fourteen'
So just print the equation to the page, store the array in $_SESSION, and then check the answer the user provides.
<?php
// array of numbers and their corresponding word versions
// you can simply do $wordNumbers[6] and get 'six'
$wordNumbers = array(
0 => 'zero',
1 => 'one',
2 => 'two',
3 => 'three',
4 => 'four',
5 => 'five',
6 => 'six',
7 => 'seven',
8 => 'eight',
9 => 'nine',
10 => 'ten',
11 => 'eleven',
12 => 'twelve',
13 => 'thirteen',
14 => 'fourteen',
15 => 'fifteen',
16 => 'sixteen',
17 => 'seventeen',
18 => 'eighteen',
19 => 'nineteen',
20 => 'twenty'
);
/*
*
* returns an array representing components of a math captcha
* [0] - first variable value, as string, like either '4' or 'four'
* [1] - second value, the operator, like '+' or 'plus'
* [2] - third value, the second variable, like 'ten' or '10'
* [3] - the answer, in numerical form, like '14'
* [4] - the answer, in text form, like 'fourteen'
*/
function getMathCaptcha(){
global $wordNumbers;
$equation = array();
// get first number, between 7 and 13 inclusive
$n1 = rand(7, 13);
$r = rand(0,1);
// return $n1 as digit or text
if ($r == 0) {
$equation[0] = $n1;
} else {
$equation[0] = $wordNumbers[$n1];
}
// get operator
$o = rand(0,1);
$r = rand(0,1);
if ($o == 0){
// subtraction
if ($r == 0) {
$equation[1] = '-';
} else {
$equation[1] = 'minus';
}
} else {
// addition
if ($r == 0) {
$equation[1] = '+';
} else {
$equation[1] = 'plus';
}
}
// get second number, between 0 and 7 inclusive, so no negative answers
$n2 = rand(1,7);
$r = rand(0,1);
// return $n2 as digit or text
if ($r == 0) {
$equation[2] = $n2;
} else {
$equation[2] = $wordNumbers[$n2];
}
// get answer
if ($o == 0){
$answer = $n1 - $n2;
} else {
$answer = $n1 + $n2;
}
// answer as digit and text
$equation[3] = $answer;
$equation[4] = $wordNumbers[$answer];
return $equation;
}
?>
have you tried a captcha method like mine below?
what are the downpoints of this captcha method
or are you specifically wanting to use a user-entry method?
How about using Captchator?
It's easy to implement and it just works! There are also code samples for PHP and Ruby out there, shouldn't be difficult to implement in other languages.
Math based captchas are weak and easy to pass, there are many spambots out there that know how to do the math :)
If I were to make a simple one, it would go along the lines of:
Make different items of categories, such as flowers, fruits, vegetables, and meats. Then design the captcha to ask for a total of a category.
For example:
Randomize the categories, choose 2 unique ones. So perhaps we got flowers and fruits.Next, ask the user: "If you have 3 roses, 4 oranges, and 6 apples, then how many fruits do you have?"
Simple pattern:
Get n-1 unique categories. Show n items, where each item belongs to one of the unique categories. Ask for a total from one category.
you can create a captcha like this on your own. All you have to do is create a function which will pick up a random number between the given list of numbers and call the function twice to pick up two random numbers.
Store the result in a session variable or any other variable so that you can verify it later.
below is an example coded in c#
Random a=new Random();
a.Next();//it will return you a non negative number
a.Next(min value,maximum value);//it will return you a number between the range specified.
Hope this helps

Resources