I want to union ranges from any Google spreadsheets.
The example
Sheet1!A:A
{12, 131, 45}
Sheet2!A:A
{12, 131, 46}
The unknown function
=formula_for_union_range(Sheet1!A:A; Sheet2!:A:A)
should return
{12, 131, 45, 12, 131, 46}
The question
How is it possible?
Just use:
={sheet1!a:a; sheet2!a:a}
You can merge them into 1 column then get the unique values. Check the following formula:
=UNIQUE({Sheet1!A:A;Sheet2!A:A})
Google Apps Script
And yet the question was about the script. I'm still successfully using the following code:
function unionRanges(e) {
var result = [];
var length = 0;
var i = 0;
try {
for (i = 0; i < arguments.length; i++)
length += arguments[i].length;
if (length > 3000) return '#BIGRANGE';
for (var i = 0; i < arguments.length; i++)
result = result.concat(arguments[i].filter(function (el) {
return el.join('').length > 0
}));
return result;
} catch (err) {
return JSON.stringify(err);
}
}
Spreadsheets feature
But, as noted above, it is easier to use {}-notation.
={ Sheet1!A1:C10 ; Sheet2!A1:C34 }
Vertical concatenation
={ Range(Cols=N) ; Range(Cols=N) }
Horizontal concatenation
={ Range(Rows=M) , Range(Rows=M) }
It's possible to combine
={ { , , } ; { , , } }
Or something more hard
={{{;;},{;;}};{{;;},{;;}};{{;;},{;;}}}
Try something like this
={
{{ 1; 2; 3},{ 4; 5; 6}};
{{ 7; 8; 9},{10;11;12}};
{{13;14;15},{16;17;18}}
}
The internal horizontal concatenation is not required
={
{ 1; 2; 3},{ 4; 5; 6};
{ 7; 8; 9},{10;11;12};
{13;14;15},{16;17;18}
}
Locale dependencies of argument delimiters
If your current locale supports , as an argument delimiter thnen you should use ; for a vertical concatenation and , for a horizontal concatenation.
Otherwise your argument delimiter is ; and you have to use ; and \ (without spaces), respectively.
Sheet 'Data 1'!A1:C20
| Name | Date | Sum |
| Ethan | 3/4/2017 | 31 |
| Logan | 3/6/2017 | 62 |
| Brian | 3/26/2017 | 61 |
| ... | ... | ... |
Sheet 'Data 2'!A1:C20
| Name | Date | Sum |
| Nathan | 3/30/2017 | 53 |
| Alyssa | 3/13/2017 | 72 |
| John | 3/24/2017 | 79 |
| Megan | 3/16/2017 | 10 |
| ... | ... | ... |
Concatenation
Vertical concatenation
={'Data 1'!A1:C20;'Data 2'!A2:C20}
Result
| Name | Date | Sum |
| Ethan | 3/4/2017 | 31 |
| Logan | 3/6/2017 | 62 |
| Brian | 3/26/2017 | 61 |
| ... | ... | ... |
| Nathan | 3/30/2017 | 53 |
| Alyssa | 3/13/2017 | 72 |
| John | 3/24/2017 | 79 |
| ... | ... | ... |
Horizontal concatenation
={TRANSPOSE('Data 1'!A1:C20),TRANSPOSE('Data 2'!A2:C20)}
Result
| Name | Ethan | Logan | Brian | ... | Nathan | Alyssa | John |
| Date | 3/4/2017 | 3/6/2017 | 3/26/2017 | ... | 3/30/2017 | 3/13/2017 | 3/24/2017 |
| Sum | 31 | 62 | 61 | ... | 53 | 72 | 79 |
More about this How to concatenate ranges in Google spreadsheets
Although a script can do this easily, I recommend using regular spreadsheet formulas, e.g.
=transpose(split(join(";";Sheet1!A:A)&";"&join(";";Sheet2!A:A);";"))
To remove duplicates, just wrap it in a unique formula:
=unique(transpose(...))
And to sort... =sort(...)
At first when I tried ={Sheet1!A:A; Sheet2!A:A}, I thought it didn't work because I could only see results from the first sheet. Turned out it was including all the blank cells too!
To filter out blank and empty cells while preserving duplicates (unlike =UNIQUE) and without repeating yourself (unlike =FILTER()), you can use =QUERY(), like so:
=QUERY(
{March!A1:Z; April!A2:Z; May!A2:Z},
"select * where Col1 != '' and Col1 is not null",
0)
(Note that I am including the header row from the first sheet, and omitting it from the other sheets).
If your sheets don't contain cells with empty text, you can omit Col1 != '' and.
Suppose you have:
A B C D E F
1: 1 2 3 4 5 6
It's possible to concatenate slices as either rows or columns.
For additional columns (same row), use a comma. ={$A1:$C1,$D1:$F1} yields:
1 2 3 4 5 6
For additional rows (same columns), use a semicolon. ={$A1:$C1;$D1:$F1} yields:
1 2 3
4 5 6
If you want to union sheets and exclude rows with empty cells use the FILTER function in your formula:
=FILTER({Sheet1!A:A;Sheet2!A:A}, {Sheet1!A:A;Sheet2!A:A}<>"")
Related
I have code similar to this:
data input;
input yr $ lob $ type $
allow_P25 los_P25 adm_P25;
cards;
2019 Com AMB 205.4 3.56 3444
2019 Med DME 34.4 1.11 533
;
run;
data results;
length perc_type $15 perc_value 8;
set input;
array change _numeric_;
do over change;
perc_type = vname(change);
perc_value = change;
output results;
end;
run;
This code creates an array of all numeric variables. However, I now need to create an array of variables with names ending in P25
Is there a way to do it using wildcards? I found some solutions on the internet in which they used wildcards, but it always seemed to be at the end of the variable name. What if I want to use the wildcard at the beginning of the variable name? I tried this (obviously, wrong solution)
data results;
length perc_type $15 perc_value 8;
set input;
array change :P25;
do over change;
perc_type = vname(change);
perc_value = change;
output results;
end;
run;
As a workaround, you can match the suffix of the _numeric_ array using prxmatch(perl_regex, string) and perform action only if a match is found.
Code
data results;
length perc_type $15 perc_value 8;
set input;
array change _numeric_;
do over change;
/* match vnames ending with P25 */
if (prxmatch("/P25$/", vname(change)) > 0) then do;
/* do whatever you want */
perc_type = vname(change);
perc_value = change;
output results;
end;
end;
run;
Output
| Obs | perc_type | perc_value | yr | lob | type | allow_P25 | los_P25 | adm_P25 |
|-----|----------:|------------|------|-----|-----:|----------:|--------:|---------|
| 1 | allow_P25 | 205.40 | 2019 | Com | AMB | 205.4 | 3.56 | 3444 |
| 2 | los_P25 | 3.56 | 2019 | Com | AMB | 205.4 | 3.56 | 3444 |
| 3 | adm_P25 | 3444.00 | 2019 | Com | AMB | 205.4 | 3.56 | 3444 |
| 4 | allow_P25 | 34.40 | 2019 | Med | DME | 34.4 | 1.11 | 533 |
| 5 | los_P25 | 1.11 | 2019 | Med | DME | 34.4 | 1.11 | 533 |
| 6 | adm_P25 | 533.00 | 2019 | Med | DME | 34.4 | 1.11 | 533 |
Notes
SAS array does not work like other languages. A SAS array is a reference to a group of variables. Therefore, if there is no magic way, just get the built-in _numeric_ group directly at first and filter the variable names subsequently.
See also the official docs in SAS regex.
There is no direct SAS syntax that allows this. Though macros have been written to deal with problems like this one.
See a few at Roger's Github here.
In rt index i have fields - fields with rt_attr_json attributes.
In this field i have such structure (collection of same blocks):
{
block_name: "a",
block_type: 1,
elements: {
{
...
}
}
}
How I can get all records from sphinx which has block_type = 1 and not empty elements in this block?
I know how this realize if I know a key of block:
where fields[0].block_type=1 and fields[0].elements is null;
I am not sure if I completely understood the question, but the following works nicely in Sphinx 3.1.1:
mysql> select * from jt;
+------+-------+-----------------------------+
| id | title | j |
+------+-------+-----------------------------+
| 1 | | {"type":1} |
| 2 | | {"type":1,"elements":[]} |
| 3 | | {"type":1,"elements":[123]} |
| 4 | | {"type":2} |
| 5 | | {"type":2,"elements":[123]} |
+------+-------+-----------------------------+
5 rows in set (0.00 sec)
mysql> select * from jt where j.type=1 and j.elements is not null;
+------+-------+-----------------------------+
| id | title | j |
+------+-------+-----------------------------+
| 2 | | {"type":1,"elements":[]} |
| 3 | | {"type":1,"elements":[123]} |
+------+-------+-----------------------------+
2 rows in set (0.00 sec)
Note that any previous versions might behave differently, as NULL handling was fixed to the point of being semi-rewritten in the most recent 3.1.1 release.
I have a table with a number of variables such as:
+-----------+------------+---------+-----------+--------+
| DateFrom | DateTo | Price | Discount | Cost |
+-----------+------------+---------+-----------+--------+
| 01jan17 | 01jul17 | 17 | 4 | 5 |
| 01aug17 | 01feb18 | 15 | 1 | 3 |
| 01mar18 | 01dec18 | 12 | 2 | 1 |
| ... | ... | ... | ... | ... |
+-----------+------------+---------+-----------+--------+
However I want to split this so I have:
+------------+------------+----------+-------------+---------+-------------+------------+----------+-------------+-------------+
| DateFrom1 | DateTo1 | Price1 | Discount1 | Cost1 | DateFrom2 | DateTo2 | Price2 | Discount2 | Cost2 ... |
+------------+------------+----------+-------------+---------+-------------+------------+----------+-------------+-------------+
| 01jan17 | 01jul17 | 17 | 4 | 5 | 01aug17 | 01feb18 | 15 | 1 | 3 |
+------------+------------+----------+-------------+---------+-------------+------------+----------+-------------+-------------+
There's a cool (not at all obvious) solution using proc summary and the idgroup statement that only takes a few lines of code. This runs in memory and you're likely to come into problems if the dataset is large, otherwise this works very well.
Note that out[3] relates to the number of rows in the source data. You could easily make this dynamic by adding a prior step that calculates the number of rows and stores it in a macro variable.
/* create initial dataset */
data have;
input (DateFrom DateTo) (:date7.) Price Discount Cost;
format DateFrom DateTo date7.;
datalines;
01jan17 01jul17 17 4 5
01aug17 01feb18 15 1 3
01mar18 01dec18 12 2 1
;
run;
/* transform data into 1 row */
proc summary data=have nway;
output out=want (drop=_:)
idgroup(out[3] (_all_)=) / autoname;
run;
I want to sum the 7 preceding values of a row as a measure like so:
| Wk_number | Value A | Measure | Array |
-------------------------------------------
| 01 | 1 | N/A# | N/A# |
| 02 | 1 | 1 | {01} |
| 03 | 10 | 2 | {01-02} |
| 04 | 3 | 12 | {01-03} |
| 05 | 5 | 15 | {01-04} |
| 06 | 10 | 20 | {01-05} |
| 07 | 1 | 30 | {01-06} |
| 08 | 4 | 31 | {01-07} |
| 09 | -10 | 34 | {02-08} |
| 10 | 3 | 26 | {03-09} |
| 11 | 2 | 18 | {04-10} |
etc...
I added the array column just to clarify the example how of the sum is comprised, notice that from wk09 it's not simply a running total.
How to do this using DAX statements?
Two ways to do this: you can either create a calculated column, or a measure.
For the column:
=CALCULATE(SUM([Value A]),FILTER(Table,Table[Wk_number]<EARLIER(Table[Wk_number]) && Table[Wk_number] >= (EARLIER(Table[Wk_number])-7)))
For the measure, it's a very similar formula but instead of using EARLIER(), we use MAX():
=CALCULATE(SUM([Value A]),FILTER(ALL(Table3),Table3[Wk_number]<MAX(Table3[Wk_number]) && Table3[Wk_number] >= (MAX(Table3[Wk_number])-7)))
Below is a screenshot of the results. A few of the numbers in your example table seem to be off based on the math:
I have been using SAS off and on for a year and I'm finally getting into arrays, macros, and all that cool stuff.
What I want to do:
I have a merged dataset with data from students in different grades on a test. I need to create different files for each grade. I don't have a grade variable to easily sort the dataset by and create different files. I do have an index of variables specific to each grade.
Example - What I have:
+-------+--------+--------+--------+--------+--------+
| ID | sc_132 | sc_139 | sc_142 | sc_143 | sc_151 |
+-------+--------+--------+--------+--------+--------+
| 16623 | 1 | 1 | 0 | . | . |
| 16624 | 1 | 0 | 0 | . | . |
| 16626 | 1 | 1 | 1 | . | . |
| 17221 | . | . | . | 1 | 0 |
| 17222 | . | . | . | 0 | 1 |
| 17225 | . | . | . | 0 | . |
+-------+--------+--------+--------+--------+--------+
Example - What I want:
+-------+--------+--------+--------+--------+--------+
| ID | sc_132 | sc_139 | sc_142 | sc_143 | sc_151 |
+-------+--------+--------+--------+--------+--------+
| 16623 | 1 | 1 | 0 | . | . |
| 16624 | 1 | 0 | 0 | . | . |
| 16626 | 1 | 1 | 1 | . | . |
+-------+--------+--------+--------+--------+--------+
+-------+--------+--------+--------+--------+--------+
| ID | sc_132 | sc_139 | sc_142 | sc_143 | sc_151 |
+-------+--------+--------+--------+--------+--------+
| 17221 | . | . | . | 1 | 0 |
| 17222 | . | . | . | 0 | 1 |
| 17225 | . | . | . | 0 | . |
+-------+--------+--------+--------+--------+--------+
Where I am:
I have a lot of variables specific to each grade, and some of the variables contain missing data, so to be thorough I should check all of the grade-specific variables and output any observations containing data in any of those fields. I could use a hideously long IF THEN statement...
DATA grade1 grade2 grade3 grade4;
SET gradeall;
IF sc_132 ^= . OR sc_139 ^= . OR (AND SO ON FOR ABOUT 34 VARIABLES) THEN OUTPUT grade1;
RUN;
But I thought this would be a good time to use an array. I can't find any easy to parse documentation about where and when you can use do loops. Using my logic of other programming languages and what I've browsed about do loops I've put together the following.
%let gr1_var = sc_132 sc_139 sc_142;
/*-GRADE SPECIFIC ARRAY REPEATED FOR OTHER GRADES -*/
DATA grade1 grade2 grade3 grade4;
SET gradeall;
PUT &gr1_var;
ARRAY grade1 [*] &gr1_var;
IF (
DO i= 1 TO (DIM(items5_all)-1);
items5_all(i) ^=. OR ;
END;
DO i= DIM(items5_all);
items5_all(i) ^=.;
END;
)
THEN OUTPUT grade1;
/*-IF THEN STATEMENT THEN REPEATED FOR OTHER GRADES-*/
run;
I was hoping this would give me the equivalent of the long IF THEN statement above without having to type it. But of course it is non-functional.
Can you even use do loops within If statements (I haven't found any examples of this)?
Does anyone have any recommendations for how to accomplish this task?
I think if you only want to output any observation which contains data in any of specific fields, you can just do a sum of array. If any observation doesn't have value for a variable, the sum is empty so this observation will not be output. No loop is needed. Just like:
%let gr1_var = sc_132--sc_142; /*for array definition, you may use "--" or "-" */
%let gr2_var = sc_143 sc_151;
DATA grade1 grade2;
SET gradeall;
ARRAY grade1 [*] &gr1_var;
ARRAY grade2 [*] &gr2_var;
if sum(of grade1(*))^=. then output grade1;
if sum(of grade2(*))^=. then output grade2;
run;
By the way, if macro is used here, there is no need to write multiple if..then and array definition.
And I don't think you can use DO LOOP inside if..else statement like what you put here.