Can anyone help me to solve the followinig MDX related problem ?
I'd need to aggregate a value over a specific set of members.
This set consists of the currentmember and all his cousins (members at the same relative position from their parents as my currentmember) from the "uncles" that are preceeding his parent.
Example :
AAA BBB CCC DDD EEE
123 123 123 123 123
If my current member is C3, my result set would be C3 + B3 + A3
Thanks in advance to the champ' that will find the solution to this !
You can use the Cousin function.
Related
I feel like my question should be easy to figure out, but I've looked around and can't seem to find out how to get a basic array spill function that produces the max value. Here's my simplified data set:
Col A
Col B
Apple
864
Carrot
189
Pear
256
Apple
975
Pear
873
Carrot
495
Apple
95
Pear
36
Carrot
804
My objective is to have a unique list of food (from Col A), that returns the max corresponding Value from Col B. The formula for unique list from Col A is easy... =UNIQUE(filter(A:A,A:A<>"")), what I'm struggling with is getting a dynamic maxifs to align with this.
To illustrate, if I put the unique function in cell D2 (thus it would spill to d4 as shown below in blue), a correct corresponding non-array function would be =MAXIFS(B:B,A:A,D2) (shown in column e). I could drag this down the remaining rows but I would like this to be dynamic as there may be more food in my data set in the future.
What I would EXPECT to work is... =filter(MAXIFS(B:B,A:A,D2:D),D2:D<>"") but this returns #Value!. By comparison, if I were to use sumif/Average, =filter(SUMIF(A:A,D2:D,B:B),D2:D<>""), I get what I WOULD expect (which really confuses me).
Is there a way to get a dynamic maxifs (or any function that produces an equal value in column E) that would spill based on unique values in column D?
try:
=QUERY({A:B}, "select Col1,max(Col2) where Col2 is not null group by Col1 label max(Col2)''")
bonus:
=QUERY({A:B}, "select Col1,max(Col2),sum(Col2) where Col2 is not null group by Col1 label max(Col2)'',sum(Col2)''")
bonus 2:
=SORTN(SORT(A1:B, 2, ), 9^9, 2, 1, 1)
2 - sort the second column of range A1:B
<empty> - or 0 or FALSE = "in descending order"
9^9 - output all rows
2 - 2nd mode of SORTN = "group by..."
1 - 1st column
1 - in ascending order
Responding to provide a more clear answer and simplification as others see this looking for same:
The easiest way to accomplish this is by using an array formula such as:
=MAX(IF($A$1:$A$7="Apple",$B$1:$B%7)) followed by CTRL-SHIFT-ENTER
A B C
1 zoo aardvark gorilla
2 =sort(A1:B1) ← aardvark gorilla zoo
What I need to do is sorting the first row into the second one, ideally placing a formula involving sort in the A2 cell.
Is there some (relatively) simple workaround that I can use to get what I want?
To process a single row, try this in cell A2:
=split(textjoin("|",1,sort(flatten(A1:C1),1,1)),"|")
or
=transpose(sort(transpose(A1:C1),1,1))
For a more complex arrayformula, use:
=arrayformula(
{
indirect("A1:"&substitute(address(1,columns(A:C),4),"1",)&"1");
substitute(
vlookup(
sequence(max(if(A:C<>"",row(A:A)))-1,columns(A:C)),
{sequence(columns(A:C)*(max(if(A:C<>"",row(A:A)))-1)),query({array_constrain(int((row(A2:A)-2)/columns(A:C))+1,columns(A:C)*(max(if(A:C<>"",row(A:A)))-1),1),query({flatten(indirect("A2:"&substitute(address(1,columns(A:C),4),"1",)&(max(if(A:C<>"",row(A:A)))-1)+1)&char(9999))},"where Col1 is not null",0)},"order by Col1,Col2",0)}
,3,0)
,char(9999),)})
An adjust your range in place of A:C.
I have explored different solutions suggestions on stackoverflow. Honestly, got a lot of #NUM! , #VALUE! Looks like I really need help on this.
Sharing my effort so far.
A B C
Doc Ref A-Ref
3904 1234 3904
3904 1237 3904-1
3904 1235 3904-2
3907 1110 3907
3907 1111 3907-1
This is the sample data that I'm working on. I'd want to sort 3 columns by descending order (2 numeric cols, Col C is not numeric because of hyphen) by only using excel formula - no VBA or SORT ribbon)
Column D = Rank of Numeric Col A - formula used is =RANK(A2,A$2:A$6)
Column E = Rank of Numeric Col B - formula used is =RANK(B2,B$2:B$E)
On Column C - since it has hyphen, - I may not be able to use RANK
Therefore not sure what will work here - [pthere was a resource about sorting text first 3 letters by desc on stackoverflow, but mine has "spl character hyphen with numbers and so it's text" - that solution won't help me]
Now after RANK, What next?
How can I ensure that Col A is ordered by descending and it's respective Col B entries is turn ordered by descending and therefore Col C.
There will be duplicates on Col A, and at the max Col B.
Col C will be unique (therefore we'll not have to create any intermediate column) but Col C can be blank as well
Please please help!
For non-numerical ranking, you may use COUNTIF.
=COUNTIF($B$2:$B$6,"<="&B2)
Hope this helps..
Hello: I have a question.
I have a sas dataset like this:
data a;
input id $ a b ;
cards;
ddd 12 1
ddd 22 1
ddd 44 2
ddd 50 1
ddd 52 1
ddd 88 2
;run;
and I expect I can use if first to flag the obs lake this:
data a;
input id $ a b flag $;
cards;
ddd 12 1 Y
ddd 22 1
ddd 44 2 Y
ddd 50 1 Y
ddd 52 1
ddd 88 2 Y
;run;
In order to do that, I sort the dataset by ID, a,b and tried to use if first.b to create flag. But it flags all the obs with Y. I think it might be the reason that I sort by a before b. But in order to keep the dataset in this order, I have to sort it by a,b. So, my question is how can I keep the order and use first.b to create the flag?
Thanks.
I'm assuming you're using set by a b; in combination with first.b. The reason first.b doesn't work in this case is because first.b will be true for the first value of b inside an a group, and in this case there is only one b within each a.
This alternative should work, it retains the previous value of b and checks it each time.
data flagged (drop=prev_b);
set a;
retain prev_b;
if b ne prev_b then flag='Y';
output;
prev_b=b;
run;
You just need to use the NOTSORTED option on the BY statement so that SAS will set the FIRST. and LAST. flags as want them.
data want ;
set a ;
by id b notsorted;
flag = first.b ;
run;
I'm looking for an algorithm to efficiently place all-day/multi-day event banners, much like the month view in Outlook or Google Calendar. I have a number of events with a begin and end date, ordered by increasing begin (and then end) date (or any other order you please, I'm gathering events from a database table). I would like to minimize the average amount of vertical space used up, because after the event banners I will need to place other events just for that day (these always come after the banners for a given date). So, for example, if I had two events, one 1/10-1/11 and one 1/11-1/15, I would prefer to arrange them like so (each column is a single day):
bbbbb
aa
and not like:
aa
bbbbb
because when I add the events just for the day (x, y, and z), I can do this (I would prefer the first, do not want the second):
bbbbb vs. aa
aa xyz bbbbb
xyz
But it isn't as simple as placing the longer events first, because with 1/10-1/11, 1/13-1/14, and 1/11-1/13, I would want:
aa cc
bbb
as opposed to:
bbb
aa cc
because this would allow for events x and y:
aa cc vs. bbb
xbbby aa cc
x y
And of course I would prefer to do this in one pass. For the data structure, I'm currently using a map from date to list, where for each day of an event I add the event to the corresponding list. So a three-day event appears in three lists,each one under one of the days in the map. This is a convenient structure for transforming the result into visual output, but I'm open to other data structures as well. I'm currently using a greedy algorithm, where I just add each event in order, but that can produce unwanted artifacts like:
aa ccc
bbbbb
dd
eeeeeeeeeeeeeeeee
This wastes a lot of space for most of the "e" event days.
Any ideas?
Here is a high-level sketch of one possible solution (using day-of-week integers instead of full-blown dates). This interface:
public interface IEvent {
public abstract int getFirst(); // first day of event
public abstract int getLast(); // last day of event
public abstract int getLength(); // total number of days
public abstract char getLabel(); // one-char identifier
// true if this and that have NO days in common
public abstract boolean isCompatible(IEvent that);
// true if this is is compatible with all events
public abstract boolean isCompatibleWith(Collection<IEvent> events);
}
must be implemented to use the algorithm expressed in the layout method below.
In addition, the concrete class must implement Comparable to create a natural order where longer events precede shorter events. (My sample implementation for the demo below used an order of descending length, then ascending start date, then ascending label.)
The layout method takes a collection of IEvent instances and returns a Map that assigns to each row in the presentation the set of events that can be shown in that row.
public Map<Integer,Set<IEvent>> layout(Collection<IEvent> events) {
Set<IEvent> remainingEvents = new TreeSet<IEvent>(events);
Map<Integer,Set<IEvent>> result = new TreeMap<Integer,Set<IEvent>>();
int day = 0;
while (0 < remainingEvents.size()) {
Set<IEvent> dayEvents = new TreeSet<IEvent>();
for(IEvent e : remainingEvents) {
if (e.isCompatibleWith(dayEvents)) {
dayEvents.add(e);
}
}
remainingEvents.removeAll(dayEvents);
result.put(day, dayEvents);
++day;
}
return result;
}
Each row is composed by selecting the longest remaining event and progressively selecting all additional events (in the order described above) that are compatible with previously-selected events for the current row. The effect is that all events "float" upward as far as possible without collision.
The following demo shows the two scenarios in your question, along with a randomly-created set of events.
Event collection:
x(1):4
b(5):2..6
y(1):5
a(2):1..2
z(1):6
Result of layout:
0 -> {b(5):2..6}
1 -> {a(2):1..2, x(1):4, y(1):5, z(1):6}
Visual presentation:
bbbbb
aa xyz
Event collection:
x(1):1
b(3):2..4
a(2):1..2
c(2):4..5
y(1):5
Result of layout:
0 -> {b(3):2..4, x(1):1, y(1):5}
1 -> {a(2):1..2, c(2):4..5}
Visual presentation:
xbbby
aa cc
Event collection:
f(2):1..2
h(2):1..2
d(4):1..4
e(4):2..5
c(1):6
a(2):5..6
g(4):2..5
b(2):0..1
Result of layout:
0 -> {d(4):1..4, a(2):5..6}
1 -> {e(4):2..5, b(2):0..1, c(1):6}
2 -> {g(4):2..5}
3 -> {f(2):1..2}
4 -> {h(2):1..2}
Visual presentation:
ddddaa
bbeeeec
gggg
ff
hh
I think in a situation like this, you're much better off making sure your data is organized properly first and then rendering it. I know you want a single pass, but I think the results would be alot better.
For instance, organize the data into the lines you'll need to have for a given day and organize the events the best way possible, starting with the longest events (don't need to be displayed first, but they do need to be organized first) and moving down to the shortest events. This will allow you to render your output accordingly not wasting any space, and avoiding those "e" event days. Additionally, then:
bbb
aa cc
or
aa cc
bbb
won't matter because x and y can always go on either side of bbb or even between aa and cc
I hope you find this helpful.