I want to understand how the reduce functions are used in Crossfilter. Namely, the
reduceAdd(p,v){...}
reduceRemove(p,v){...}
and
reduceInitial(p,v){...}
in
group.reduce(reduceAdd, reduceRemove, reduceInitial);
From Crossfilter's API reference, I understand that the p and v arguments represent the group and dimension value respectively.
From what I understand, the return value of the reduce functions determine what the groupValue should be changed to after the element is added or removed from the group. Is this correct?
Also, what is the reduceInitial function for?
That is correct, if you substitute "bin value" for "groupValue" in what you wrote.
A group is made of an array of bins; each bin is a key-value pair. For every group, all rows of the data supplied to crossfilter will "fall into" one bin or another. The reduce functions determine what happens when a row falls into a bin, or is removed from it because the filters changed.
Crossfilter determines which bin any row falls into by using using the dimension value accessor and the group value function.
When are reduction functions called?
When a crossfilter initializes a new group, it adds all the currently matching rows of the data to all the groups. The group determines a key for each row by using the dimension value accessor and the group value function. Then it looks up the bin using that key, and applies the reduceAdd function to the previous bin value and the row data to produce the new bin value.
When any filter on any dimension of the crossfilter changes value, some rows will stop matching and some rows will start matching the new set of filters. The rows that stop matching are removed from the matching bin using the reduceRemove function, and the rows that start matching are added using the reduceAdd function.
When a row is added, some groups may not already have a bin which matches the key for that row. At that point a new bin must be initialized and at that point the group calls reduceInitial to get the user-specified blank value for the bins of that group.
Crossfilter's group.reduce compared to Array.reduce
The reduceAdd and reduceRemove functions are similar to the functions you would pass to Javascript's Array.reduce function. The first parameter p takes the previous value of the bin, and the second paramter v takes the current row data being considered.
In contrast to Array.reduce, in group.reduce
values can be removed as well as added
the initial value is produced by the reduceInitial function instead of being passed to reduce
it doesn't perform the aggregation immediately; instead you are supplying functions that will get called whenever filters change or data is added or removed
Related
The A column is first name and the B column is last name in the spreadsheet I'm manipulating. In the other sheet it's the full name(but not necessarily just firstname + lastname)
HC is the spreadsheet I need to get the data from. This code will work if the person has a unique first name that is the same in both sheets : =VLOOKUP(""&A2&"",HC!$C$1:$I$400,7,False) but this isn't enough in my case. The *s known as wildcards check if this string is contained in another string regardless of it's position.
I tried =VLOOKUP(""&A5&" "&B5&"",HC!$C$1:$I$400,7,False) but that means the two strings have to occur one after the other. I need it to return if search_key1 is contained within the string regardless of accents(á or a) or case (A or a) and the same for search_key2 e.g. the string could be "Seárch_key1 kdslfj SEARCH_KEY2 akldfj" and this would return True and then give the 7th column.
function VLOOKUP2(search_key1,search_key2,range,index){
//is search_key1 contained in one of the cells in the range if so is search_key2 also contained in one of the cells in the range regardless of capitilization and diacritical marks
// return the column specified by the index parameter
}
I know you're asking for a custom function, but I think you could do this with two existing vlookup functions.
If your data on sheet HC looks like this:
Then on your lookup sheet, try this in cell C1 (deleting everything below):
=arrayformula({"Result";if(A2:A<>"",iferror(iferror(vlookup("*"&A2:A&"*"&B2:B&"*",{HC!C:I},7,0),vlookup("*"&B2:B&"*"&A2:A&"*",{HC!C:I},7,0)),),)})
HELP NOTES
The inital vlookup tries to match "*"&A2:A&"*"&B2:B&"*" in {HC!C:I}. {} is used to create an array.
If not, then the iferror tries another vlookup to match "*"&B2:B&"*"&A2:A&"*".
Another iferror deals with no match, removing #N/A.
Then the if(A2:A<>"" only tries the above formula if there is a corresponding value in the same row, in Col A.
The final array {} places "Result" at the top of the column, with the main formula below. After the heading text, ; forces a return in the array.
Within the vlookup, 0 denotes false. 1 would be true.
I am attempting to make Conway's Game of Life with React. I have an array of boolean values representing the grid in state, and then render an "alive" or "dead" cell for true or false values.
The solution I came up with for counting the surrounding number of "alive" neighbours to determine whether a cell is alive or dead in the next generation includes treating corner and edge cells separately from the rest of the middle cells.
In order to do this, I tried making a copy of the grid array and set the elements representing the corner and edge cells to null after counting their neighbours. Then, I was going to iterate over the remaining middle cells and count their surrounding neighbours.
However, after changing elements to null in the copy of the grid, the original grid in state is also changing. Can anyone explain this behaviour?
console.log(this.state.grid[topLeftCorner]); // false
innerSquare[topLeftCorner] = null;
console.log(this.state.grid[topLeftCorner]); // null
https://codepen.io/Egeroth/pen/jaeYwR
When you assign a existing array to another variable, you do not get a copy, simply two variables which point to the same array. If you want to create a separate copy then consider using array.slice() and see Copying array by value in JavaScript for more details.
In the countNeighbours() method you are creating copy of the gird in a wrong way:
let innerSquare = this.state.grid;
This will copy only reference to the grid, not clone it.
You should write: let innerSquare = this.state.grid.slice(0); instead.
Adding .slice(0) will actually clone the grid into a new array.
I have a Google Sheets spreadsheet in which I'd like to pas a range of that row as an array to a custom function (for example, d37:m37). This works fine if you pass a range of a column (for example, d4:d37), but apparently rows behave differently than columns in this regard.
The only workaround I have found is to pass a two dimensional range (for example, d36:m37) and then within the custom function ignore all but the last row of this 2 dimensional "array".
Is there no way to get the same behavior from rows as from columns, and simply pass a range of a row in and have it treated as an array?
When you call a custom function with a range as a parameter, the function gets a two-dimensional array. For example,
range A1:B2 is represented as [['a1', 'b1'], ['a2', 'b2']] (where the strings are placeholders for actual content of those cells)
range A1:B1 (a row) is represented as [['a1', 'b1']]
range A1:A2 (a column) is represented as [['a1'], ['a2']]
as an exception, a single-cell range, such as A1, passes the value in that cell directly, not an array.
As you can see, the array structure is different for row-ranges and column-ranges. A custom function can be written to handle all of the above cases appropriately. But if your custom function is such that it expects a column range, there is an easy workaround: use the transpose to turn a row into a column, e.g.,
=customfunction(transpose(D37:M37))
With the update function, I'm currently getting the number of the affected rows. Is there any way I can get the key and values of that row instead of the count?
It's possible in Postgres using the options.returning: true as documented in the update API.
Update multiple instances that match the where options. The promise
returns an array with one or two elements. The first element is always
the number of affected rows, while the second element is the actual
affected rows (only supported in postgres with options.returning
true.)
Together with the number of affected rows you are getting in the array, the second parameter is the affected rows you want.
The following program (taken from a tutorial) prints the numbers in an array in order from lowest to highest. In this case, the result will be 2,4,5,13,31
My question relates to the paramaters "a" and "b" for the function compareNumbers. When the function is called in numArray.sort(compareNumbers) what numbers will be the parameters a and b for the function. Does it just move along the array. For example, start with a=13 and b=2? After that, does the function run again comparing a=2 and b=31? or would it next compare a=31 and b=4?
Can someone please explain how that part works and also how it manages to sort them from lowest to highest? I don`t see how the function manages to do the necessary calculations on the numbers in the array.
function compareNumbers(a,b) {
return a - b;
}
var numArray = [13,2,31,4,5];
alert(numArray.sort(compareNumbers));
The particular pairs that get passed in depend on the sorting algorithm being used. As the algorithm tries to go about sorting the range, it needs to be able to compare pairs of values to determine their ordering. Whenever this happens, it will call your function to get that comparison.
Because of this, without inside knowledge about how the sorting algorithm works, you cannot predict what pairs will get compared. The choice of algorithm will directly determine what elements get compared and in what order.
Interestingly, though, you can actually use the comparison function to visualize how the sort works or to reverse-engineer the sorting algorithm! The website sortviz.org has many visualizations of sorting algorithms generated by passing custom comparators into sorting functions that track the positions of each element. If you take a look, you can see how differently each algorithm moves its elements around.
Even more interestingly, you can use comparison functions as offensive weapons! Some sorting algorithms, namely quicksort, have particular inputs that can cause them to run much more slowly than usual. In "A Killer Adversary for Quicksort," the author details how to use a custom comparator to deliberate construct a bad input for a sorting algorithm.
Hope this helps!
The two parameters will be elements of your array. The system will compare enough pairs to be able to sort them correctly. Nothing else is guaranteed.
There are lots of things the sort method could be doing under the hood; see, e.g., http://en.wikipedia.org/wiki/Sorting_algorithm for some of them. Most Javascript implementations probably use some variant of either quicksort or mergesort.
(Here are super-brief descriptions of those. Quicksort is: pick an element in the array, rearrange the array to put everything smaller than that in front of everything larger, then sort the "smaller" and "larger" bits. Mergesort is: sort the first half of the array, sort the second half of the array, and then merge the two sorted halves. In both cases you need to sort smaller arrays, which you do with the same algorithm until you get to arrays so small that sorting them is trivial. In both cases, good practical implementations do all sorts of clever things I haven't mentioned.)
It will be called for all pairs of a,b that sorting algorithm need to get all array sorted. Check out http://en.wikipedia.org/wiki/Sorting_algorithm for brief list of sorting algorithms.
When you pass a function to Array.sort(), it expects two parameters and returns a numerical value.
If you return a negative value, the first parameter will be placed before the second parameter in the array.
If you return a positive value, the first parameter will be placed after the second parameter in the array.
If you return 0, they will stay in their current position.
By doing return a - b;, you are returning a negative number if a is less than b (2 - 13 = -11), a positive number if b is less than a (13 - 2 = 11), and zero if they are even (13 - 13 = 0).
As far as which numbers are compared in what order, I believe that is up to the javascript engine to determine.
Check out the documentation on javascript array sorting at the MDC Doc Center for more detailed information.
https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/sort
(BTW, I always check the MDC Doc Center for any questions about how javascript works, they have the best information on the language AFAIK.)