When is a Perl 6 array clone not a clone? - clone

If I put a list in an array variable and clone it into another array variable, the two are distinct:
my #original = 1, 3, 7;
my #clone = #original.clone;
#original[*-1] = 'Dog';
say "original is finally <#original[]> ({#original.^name})";
say "clone is finally <#clone[]> ({#clone.^name})";
The output shows that they don't affect each other:
original is finally <1 3 Dog> (Array)
clone is finally <1 3 7> (Array)
However, if I put an Array in a scalar variable, the clone doesn't keep the two separate. Changing one changes the other:
my $original = [ 1, 3, 7 ];
say "original is <$original[]> ({$original.^name}) with {$original.elems} values";
my $clone = $original.clone;
say "clone is <$clone[]> ({$clone.^name}) with {$clone.elems} values";
if $original eqv $clone {
say "The original and clone have the same values!";
}
if $original === $clone {
say "The original and clone are the same object!";
}
if $original =:= $clone {
say "The original and clone are the same container!";
}
$original[*-1] = 'Dog';
say "original is finally <$original[]> ({$original.^name}) with {$original.elems} values";
say "clone is finally <$clone[]> ({$clone.^name}) with {$clone.elems} values";
The output shows that the original and the clone are still linked, but curiously they aren't the same object or container:
original is <1 3 7> (Array) with 3 values
clone is <1 3 7> (Array) with 3 values
The original and clone have the same values!
original is finally <1 3 Dog> (Array) with 3 values
clone is finally <1 3 Dog> (Array) with 3 values
This one works, where the clone is assigned to an array variable:
my $original = [ 1, 3, 7 ];
my #clone = $original.clone;
$original[*-1] = 'Dog';
say "original is finally <$original[]> ({$original.^name})";
say "clone is finally <#clone[]> ({#clone.^name})";
But when the original is an array and the clone is assigned to a scalar variable, it doesn't work:
my #original = 1, 3, 7;
my $clone = #original.clone;
#original[*-1] = 'Dog';
say "original is finally <#original[]> ({#original.^name})";
say "clone is finally <$clone[]> ({$clone.^name})";
This is Rakudo 2017.01.

In Rakudo 2017.04, this is no longer a problem. I get the expected output:
original is <1 3 7> (Array) with 3 values
clone is <1 3 7> (Array) with 3 values
The original and clone have the same values!
original is finally <1 3 Dog> (Array) with 3 values
clone is finally <1 3 7> (Array) with 3 values

Related

Unable to check if a list of int is completely contained in another int list

I have a list of int that represents service ids. and I want to make sure that all of those ids exist in the database.
In other words , I want to scan the list of ids and the table of services to make sure that all of these ids exist in the database.
I tried this :
List<int> ids;//[1,52]
var x = _context.Services.Any(s => ids.Contains(s.Id));//service ids = [1,2,3]
but it returned True , which is not the desired output.
I've also tried it this way :
_context.Services.Any(s => ids.Any(id => id == s.Id)!=null);
and this way
_context.Services.Any(s => ids.Any(id => id == s.Id)!=null);
with no luck as well. what is the right way to do it? I'm using EFCore 3.1.8
Normally you would use Queryable.Except for this.
If you have two sequence of items, and you do A except B, then if you have nothing left, then apparently every item from A is also an item in B.
IEnumerable<int> requiredIds = ...
IQueryable<int> serviceIds = dbContext.Services.Select(service => service.Id);
bool someRequiredIdsMissing = requiredIds.Except(serviceIds).Any();
Alas, your A is local and your B is in the database. So I guess this won't work.
What you can do, is to keep only Service Ids that are in the list of required Ids, and count them. If there are less, then apparently some requiredIds are not in serviceIds.
var requiredServiceIds = serviceIds.Where(serviceId => requiredIds.Contains(serviceId);
bool allRequiredAvailale = requiredServiceIds.Count() != requiredIds.Count();
Example:
IEnumerable<int> requiredIds = new [] {1, 2, 7, 20};
Total: 4 elements
Your service Ids are: 1 2 4 5 8 20 25
requiredServiceIds : 1 2 20: total 3 elements
So allRequiredAvailale is false;
Example 2:
Your service Ids are: 1 2 4 5 7 8 20 25
requiredServiceIds : 1 2 7 20: total 4 elements
So allRequiredAvailale is true;

Laravel Eloquent group results by relation

I am struggling to get Laravel Eloquent to retrieve and group results in the way that i'd like.
Basically I am creating a 'My Agenda' page which shows all task in order of their due date, but grouped together if 2 or more Tasks (in order) belong to the same Stage, and likewise if 2 or more stages belong to the same project.
My data is Projects -> (has many) Stages -> (has many) Tasks
I would like to output my data as follows:
Project B
Stage 2
Task 1 (due 1st Sep)
Task 3 (due 2nd Sep)
Stage 1
Task 2 (due 3rd Sep)
Project A
Stage 1
Task 2 (due 4th Sep)
Project B <---- repeated as Project A has a stage->task due before these tasks due
Stage 3
Task 2 (due 5th Sep)
Project A <---- repeated as Project B has a stage->task due before
Stage 1 <---- repeated
Task 1 (due 6th Sep)
Any ideas how I can achieve this? I am open to doing this on the front end with JS/Vue/Lodash.
Thanks in advance!
M
I think you can do it this way:
First, let's combine all the tables with JOIN. If you want to see all projects and stages that don't have any relational data, you can use LEFT JOIN, or maybe RIGHT JOIN, I don't know which one will work.
$tasks = Task::orderBy("due")
->join("stages", "stages.id", "=", task.stage_id)
->join("projects", "projects.id", "=", stages.project_id)
->select("pick the columns you want to have")
->get();
I think you should aim for this type of array as your output, so you won't have any issues because of the repeated key names.
/*
$output = [
[
'project'=> A,
'stages'=> [
stage_name => [task 1, task 2],
stage_name => [task 4, task 8],
],
],
[
'project'=> B,
'stages'=> [
stage_name => [task 5],
],
],
[...]
];
*/
To create that type of array, the function down below should work.
$output = [];
foreach($tasks => $task) {
$project = $task['project_name'];
$lastEntry = $output[count($output) - 1];
if ( count($output) > 0 && $lastEntry['project'] == $project) {
// this means $task should be inserted in the last array.
// You should check for stages.
if (array_key_exists($task['stage_name'], $lastEntry['stages'])) {
$lastEntry['stages'][$task['stage_name']][] = $task;
} else {
$lastEntry['stages'][$task['stage_name']] = [$task];
}
// I think $lastEntry['stages'][$task['stage_name']][] = $task; will work without checking stage names, but I can't be sure, you need to try it.
} else {
// This means you should create a new item in $output.
$output[] = [
'project' => name,
'stages' => [
'stage_name' => [$task];
]
]
}
}
I created those codes here directly. There can be typos and everything, but the logic should work.

JSON is object instead of array, if array_diff returns assoc array on Collection->toArray()

My issue is in my json I am expecting an array, but am getting an object.
Details:
I have an array of numbers:
$numbers = [1];
I select from relationship, the "drawn numbers":
$drawnNumbers = Ball::whereIn('number', $numbers)->where('game_id', $card->game->id)->get()->map(function($ball) {
return $ball->number;
})->toArray();
I do a ->toArray() here. I want to find the numbers in $numbers that do not occur in $drawnNumbers. I do so like this:
$numbersNotYetDrawn = array_diff($numbers, $drawnNumbers);
My method then return $numbersNotYetDrawn (my headers accept is application/json).
So now the issue. When $drawnNumbers is an empty array, then the printed json is a regular array like this:
[
1
]
However if the relationship returns $drawnNumbers to be an array with numbers, then json is printed as an object:
{
"0" => 1
}
Does anyone know why this is? Anyway to ensure that json is array?
Edit:
Here is my actual data:
$drawnNumbers = Ball::whereIn('number', $numbers)->where('game_id', $card->game->id)->get()->map(function($ball) {
return $ball->number;
})->toArray();
$undrawnNumbers = array_diff($numbers, $drawnNumbers);
// $undrawnNumbers = array_values(array_diff($numbers, $drawnNumbers)); // temp fix
Replace
$numbersNotYetDrawn = array_diff($numbers, $drawnNumbers);
with
$numbersNotYetDrawn = array_values(array_diff($numbers, $drawnNumbers));
to make sure element keys are reset and array is treated as a simple list and serialized to a JSON list - instead of being treated as an associative array and serialized to a JSON object.
I recently had this same problem and wondered the same thing.
I solved it by adding "array_values", but I was wondering how to reproduce it.
I found it that it is reproduced when array_diff removes an element from the array that isn't the last element. So:
>>> $x
=> [
1,
2,
3,
4,
5,
]
>>> array_diff($x, [5]);
=> [
1,
2,
3,
4,
]
>>> array_diff($x, [1]);
=> [
1 => 2,
2 => 3,
3 => 4,
4 => 5,
]

Activerecord: map one to one and retain duplicates

I have an array with User IDs:
UserID = [
1
2
3
4
5
3
2
2
3]
I have a table that maps User ID to User Email. I'm trying to match IDs to Emails but retain duplicates so I end up with:
[
1#me.com
2#me.com
3#me.com
4#me.com
5#me.com
3#me.com
2#me.com
2#me.com
3#me.com]
When I try to pluck or map it like:
UserInfo.where(:id => UserID).pluck(:email)
I end up with:
[
1#me.com
2#me.com
3#me.com
4#me.com
5#me.com]
How can I get the table I'm looking for?
You will have to loop
ids.map{|id| UserInfo.find(id: id).email }
But of you have tons of ids you may want to optimize it by loading first just the records you need
email_hash = UserInfo.where(id: ids).inject({}) {|h, v| h[v.id] = v.email; h;}
result = ids.map{|id| email_hash[id]}

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