Excel: How to add two numbers that has unit prefixes? - excel

I'm trying to add numbers that have the unit prefixes appended at the end (mili, micro, nano, pico, etc). For example, we have these two columns below:
Obviously doing something like =A2+A3+A4 and =B2+B3+B4 would not work. How would you resolve this? Thanks

Assuming you don't have excel version constraints, per the tags listed in your question. Put all the suffixes as delimiters inside {} delimited by a comma as follow in TEXTSPLIT, then define the conversion rules in XLOOKUP. We use SUBSTITUTE(col, nums, "") as input of XLOOKUP to extract the unit of measure.
=BYCOL(A2:B4, LAMBDA(col, LET(nums, 1*TEXTSPLIT(col,{"ms","us"},,1),
units, XLOOKUP(SUBSTITUTE(col, nums, ""), {"us";"ms"},{1;1000}),
SUM(nums * units))))
The above formula converts the result to a common unit of microseconds (us), i.e. to the lower unit, so milliseconds get converted by multiplying by 1000. If the unit of measure was not found it returns #N/A, it can be customized by adding a fourth parameter to XLOOKUP. If you want the result in milliseconds, then replace: {1;1000} with {0.001;1} or VSTACK(10^-3;1) for example.
If you would like to have everything in seconds, you can use the trick of using power combined with the XMATCH index position, to generate the multiplier. I took the idea from this question: How to convert K, M, B formatted strings to plain numbers?, check the answer from #pgSystemTester (for Gsheet, but it can be adapted to Excel). I included nanoseconds too.
=BYCOL(A2:B4,LAMBDA(col,LET(nums,1*TEXTSPLIT(col,{"ms","us"},,1),
units, 1000^(-IFERROR(XMATCH(RIGHT(col,2), {"ms";"us";"ns"}),0)),
SUM(nums * units))))
Under this approach, seconds is the output unit, because it is not part of the XMATCH lookup_array input argument, the multiplier will be 1 (as a result of 1000^0), so no units or seconds (s) will be treated the same way.
Notes:
In my initial version I used INDEX, but as #P.b pointed out in the comments, it is not really necessary to remove the second empty column, instead, we can use the ignore_empty input argument from TEXTSPLIT. Thanks
You can use TEXTBEFORE instead of TEXTSPLIT, as follows: TEXTBEFORE(A2:A4,{"ms","us"})

Related

How to sort rows in Excel without having repeated data together

I have a table of data with many data repeating.
I have to sort the rows by random, however, without having identical names next to each other, like shown here:
How can I do that in Excel?
Perfect case for a recursive LAMBDA.
In Name Manager, define RandomSort as
=LAMBDA(ζ,
LET(
ξ, SORTBY(ζ, RANDARRAY(ROWS(ζ))),
λ, TAKE(ξ, , 1),
κ, SUMPRODUCT(N(DROP(λ, -1) = DROP(λ, 1))),
IF(κ = 0, ξ, RandomSort(ζ))
)
)
then enter
=RandomSort(A2:B8)
within the worksheet somewhere. Replace A2:B8 - which should be your data excluding the headers - as required.
If no solution is possible then you will receive a #NUM! error. I didn't get round to adding a clause to determine whether a certain combination of names has a solution or not.
This is just an attempt because the question might need clarification or more sample data to understand the actual scenario. The main idea is to generate a random list from the input, then distribute it evenly by names. This ensures no repetition of consecutive names, but this is not the only possible way of sorting (this problem may have multiple valid combinations), but this is a valid one. The solution is volatile (every time Excel recalculates, a new output is generated) because RANDARRAY is volatile function.
In cell D2, you can use the following formula:
=LET(rng, A2:B8, m, ROWS(rng), seq, SEQUENCE(m),
idx, SORTBY(seq, RANDARRAY(m,,1,m, TRUE)), rRng, INDEX(rng, idx,{1,2}),
names, INDEX(rRng,,1), nCnts, MAP(seq, LAMBDA(s, ROWS(FILTER(names,
(names=INDEX(names,s)) * (seq<=s))))), SORTBY(rRng, nCnts))
Here is the output:
Update
Looking at #JosWoolley approach. The generation of the random sorting can be simplified so that the resulting formula could be:
=LET(rng, A2:B8, m, ROWS(rng), seq, SEQUENCE(m), rRng,SORTBY(rng, RANDARRAY(m)),
names, TAKE(rRng,,1), nCnts, MAP(seq, LAMBDA(s, ROWS(FILTER(names,
(names=INDEX(names,s)) * (seq<=s))))), SORTBY(rRng, nCnts))
Explanation
LET function is used for easy reading and composition. The name idx represents a random sequence of the input index positions. The name rRng, represents the input rng, but sorted by random. This sorting doesn't ensure consecutive names are distinct.
In order to ensure consecutive names are not repeated, we enumerate (nCnts) repeated names. We use a MAP for that. This is a similar idea provided by #cybernetic.nomad in the comment section, but adapted for an array version (we cannot use COUNTIF because it requires a range). Finally, we use SORTBY with input argument by_array, the map result (nCnts), to ensure names are evenly distributed so no consecutive names will be the same. Every time Excel recalculate you will get an output with the names distributed evenly in a different way.
Not sure if it's worth posting this, but I might as well share the results of my research such as it is. The problem is similar to that of re-arranging the characters in a string so that no same characters are adjacent The method is just to insert whichever one of the remaining characters (names) has the highest frequency at this point and is not the same as the previous character, then reduce its frequency once it has been used. It's fairly easy to implement this in Excel, even in Excel 2019. So if the initial frequencies are in D2:D8 for convenience using Countif:
=COUNTIF(A$2:A$8,A2)
You can use this formula in (say) F2 and pull it down:
=INDEX(A$2:A$8,MATCH(MAX((D$2:D$8-COUNTIF(F$1:F1,A$2:A$8))*(A$2:A$8<>F1)),(D$2:D$8-COUNTIF(F$1:F1,A$2:A$8))*(A$2:A$8<>F1),0))
and similarly in G2 to get the ages:
=INDEX(B$2:B$8,MATCH(MAX((D$2:D$8-COUNTIF(F$1:F1,A$2:A$8))*(A$2:A$8<>F1)),(D$2:D$8-COUNTIF(F$1:F1,A$2:A$8))*(A$2:A$8<>F1),0))
I'm fairly sure this will always produce a correct result if one is possible.
HOWEVER there is no randomness built in to this method. You can see if I extend it to more data that in the first several rows the most common name simply alternates with the other two names:
Having said that, this is a bit of a worst case scenario (a lot of duplication) and it may not look too bad with real data, so it may be worth considering this approach along with the other two methods.

Find most common lotto numbers

For each lotto game, there is six numbers drawn in excel columns E-J. My target is to list and sort most frequent numbers drawn in rage of E2:J27. How is that possible using formula? I've tried many formulas and MODE method doesn't working.
I've tried:
=MODE(IF(ISERROR(MATCH($E$2:$J$27,D$30:D30,0)),$E$2:$J$27))
or
=IFERROR(MODE(IF(COUNTIF(D$30:D30,$E$2:$J$27)={0},$E$2:$J$27)),"")
End result should look like:
Number
Draws
12
14
24
17
You can try something like this for example:
=LET(flatten, TEXTSPLIT(TEXTJOIN(";",,A1:F27),,";"),
numUq, UNIQUE(flatten), matches, XMATCH(flatten,numUq),
SORT(HSTACK(numUq, DROP(FREQUENCY(matches, UNIQUE(matches)),-1)),2,-1)
)
A second approach using COUNTIF is the following:
=LET(rng, A1:F27, counts, COUNTIF(rng,UNIQUE(rng)),
flattenNums, TEXTSPLIT(TEXTJOIN(";",,rng),,";"),
flattenCnts, TEXTSPLIT(TEXTJOIN(";",,counts),,";"),
SORT(UNIQUE(HSTACK(flattenNums, flattenCnts)),2,-1)
)
Note: See note at the end, both solutions can be simplified replacing TEXTSPLIT (O365 version 2022) with TOCOL (O365 2021 version). If for your excel version HSTACK is not available (O365 2022 version), you can use CHOOSE instead (here is explained how).
and here is the output:
Note: Highlighted number 6 (highest number of draws [8]) and 45 (4) for testing purpose of my sample (generated using ROUND(49*RAND(),0)).
Explanation
First Solution
Using LET for easy reading and composition. We define the following variables. We flatten the input to be able to obtain unique Lotto numbers in the range:
flatten, TEXTSPLIT(TEXTJOIN(";",,A1:F27),,";")
Then the unique numbers:
numUq, UNIQUE(flatten)
Then the matches we have based on unique numbers:
matches, XMATCH(flatten,numUq)
With the matches we can calculate the frequency (we cannot use COUNTIF because it expects as input argument a range and we have an array).
Now we are ready to calculate the frequency via FREQUENCY of the matches found:
FREQUENCY(matches, UNIQUE(matches))
We use DROP to remove the last row of the result. It represents the last bins (number greater than the highest count, which out of our range numbers, so we don't need it).
Finally HSTACK to combine all the information and to SORT by descending draws.
Second Solution
Simpler, but I found it latter. I realized we can use COUNTIF first (using a range, and flatten it latter), for both numbers and counts. Repeated numbers will appear more than once with the same count, so we just need to remove such rows via UNIQUE.
Notes:
For some of the functions used here (TEXTSPLIT, DROP, HSTACK, etc.). Please check Function availability for your Excel version or here organized by version.
As #Max pointed out in the comment. Flatten a range can be simplified via TOCOL so expressions like this: TEXTSPLIT(TEXTJOIN(";",,rng),,";") can be simplified as follow: TOCOL(rng).

Count the number of individual entries in a cell

Is it possible to count the number of individual entries in a cell?
For example 2+2+4-1 = 4 entries
Using the count formula counts the entries as 1
I want to calculate the number of adjustments made in a particular period.
Each +/- in an individual cell represents 1 adjustment.
Assuming you're referring to a text cell, the trick is to count the symobols you'd like to find. Before we dig into that, if you want to enter this data as text, you can use the ` symbol (Usually to the left of the 1 key on your keyboard) before entering your text to make sure it gets processed as text.
If you want to verify that it is text, you can use the TYPE function and look for a return result of 2 (check the link for other possible return types)
There are no direct functions to count characters in Excel, so the trick is to find the length of the original text and subtract it from the length of a new text where you have removed all of the special characters. You mentioned you were trying to count the entries (i.e. the numbers), but you said your goal was to ultimately count the number of '+/-' operations. Since counting numbers can be tricky with excel formulas (since we'll get hung up on 2 and 3 digit numbers), I am going to approach this problem from the perspective of counting the operations you are looking for. So here is a basic example:
length("2+1") = 3
- length("21") = 2 (we replaced the + with "" [blank])
= 1
So we know there is 1 '+' since we replaced it. The appropriate functions used to accomplish this are LEN and SUBSTITUTE
Since you can only find one symbol at a time using the SUBSTITUTE function, we must take the output of the first formula, and give it to the second formula, and so on and so forth. Ultimately, we can put together as many functions as we need to achieve the desired result.
So we start with + for your example (And assuming your data is in A1)
=LEN(A1)-LEN(SUBSTITUTE(A1,"+",""))
which gives us a result of 2. But we also need to find the - symbol. So we wrap another SUBSTITUTE:
=LEN(A1)-LEN(SUBSTITUTE(SUBSTITUTE(A1,"+",""),"-",""))
You have said you wanted to count the number of +/- in the cell, and this does accomplish that, but if you want to expand it to more mathematical operators, you simply add more SUBSTITUTE functions (here is a complete function where I've added * and /)
=LEN(A1)-LEN(SUBSTITUTE(SUBSTITUTE(SUBSTITUTE(SUBSTITUTE(A1,"+",""), "-",""),"*",""),"/",""))
Well, this formula would replace all your numbers with "" and then Count the +/- and adds one, should do it, but is ugly:
=LEN(SUBSTITUTE(SUBSTITUTE(SUBSTITUTE(SUBSTITUTE(SUBSTITUTE(SUBSTITUTE(SUBSTITUTE(SUBSTITUTE(SUBSTITUTE(SUBSTITUTE(A1;"0";"");"1";"");"2";"");"3";"");"4";"");"5";"");"6";"");"7";"");"8";"");"9";""))+1
Could probably be done with RegEx, but I don't know how to do that in formulas
This makes 31+12+3-4 to ++-, Counts the LEN (3) and adds 1

Finding the right range from excel table

What is the best way to find the right column for the travelled miles using visual basic coding or some excel function and return the price from that column? HLOOKUP can't be used here because the lookup value isn't exact and the ranges in the table are also not with specific intervals (If they were, I could use e.g. FLOOR(travelled miles/100)*100 and find the price with HLOOKUP). Obviously, it's easy to find the price manually with a small table but with a big table computer will be faster.
Note that, if x is between a and b, then MEDIAN(x,a,b)=x. Combine this with some nested IFs:
=IF(MEDIAN(B5,B1,C1-1)=B5,B2,IF(MEDIAN(B5,C1,D1-1)=B5,C2,IF(MEDIAN(B5,D1,E1-1)=B5,D2)))
I'm on my phone, so just done the first three cases, but hopefully you can see how it continues.
(should note you need to remove the dashes for this to work)
Edit:
I also want to answer your question in the comments above. You can use the following to keep the dash, but get a number to work with.
Assume cell A1 has got the value 10-. We can use the FIND function to work out where the - occurs and then use the LEFT function to only return the characters from before the dash:
=LEFT(A1,FIND("-",A1)-1)
This will return the value 10, but it will return it as a string, not a number - basically Excel will think it is text. To force Excel to consider it as a number, we can simply multiply the value by one. Our formula above therefore becomes:
=(LEFT(A1,FIND("-",A1)-1))*1
You may also see people use a double minus sign, like this:
=--LEFT(A1,FIND("-",A1)-1)
I don't recommend this because it's a bit complex, but combining with the formula above would give:
=IF(MEDIAN(B5,--LEFT(B1,FIND("-",B1)-1),--LEFT(C1,FIND("-",C1)-1)-1)=B5,B2,IF(MEDIAN(B5,--LEFT(C1,FIND("-",C1)-1,--LEFT(D1,FIND("-",D1)-1-1)=B5,C2,IF(MEDIAN(B5,--LEFT(D1,FIND("-",D1)-1,--LEFT(E1,FIND("-",E1)-1-1)=B5,D2)))

SumProduct Using Multiple Criteria Returning Too Much Data

Although this question has been asked and answered, (Stack Overflow is where I learned how to implement SP), an issue has come up which I can't figure out.
I'm using SP to sum shipments within a pivot table using a product number (with wild-cards), and a specific date. For instance, part numbers can be "AX10235-HP", "AX11135-HP", "AX10235-HP2", "AX10235-HPSPARE" or TP10101-IBM. (There are a large variety of numbers.)
So in this case I want to sum the qty shipments of "AX???35-HP". I wish to sum just the first 2 parts in my short list. However, the command used causes all the parts to sum except the *-IBM number; as if there was a wild-card at the end of the number. In other words "AX???35-HP" is the same as "AX???35-HP*". I've tried wrapping the value in quotes but it takes uses the quotes literally so fails.
This is the function
SUMPRODUCT((S_PART_DATA)*(ISNUMBER(SEARCH($A6,S_PART_RANGE))*(S_PART_DATES=T$4)))
S_PART_DATA array of Shipments,
S_PART_RANGE array of list of part numbers,
S_PART_DATES array of Dates shipments were made
It works the way you describe because SEARCH function finds $A6 within other text, hence it may not be an exact match - better to use SUMIFS function like this:
=SUMIFS(S_PART_DATA,S_PART_RANGE,$A6,S_PART_DATES,T$4)
Assuming all named ranges are the same size and A6 contains the value AX???35-HP
If that doesn't work try this version
=SUMPRODUCT(S_PART_DATA*ISNUMBER(SEARCH("^"&$A6&"^","^"&S_PART_RANGE&"^"))*(S_PART_DATES=T$4))
concatenating the ^ values means you will [probably] only get exact matches

Resources