# Elegantly pairing up mismatched lists

HistogramList returns a list of bin boundaries and a list of counts. There is one more boundary than counts, and I'd like to pair them up so I can feed it into ListLinePlot and get an alternative view of a histogram. Here's some code that will do this:

{bins, counts} = N[HistogramList[RandomVariate[NormalDistribution[5, 2], 100]]]

(* => {{0., 2., 4., 6., 8., 10.}, {13., 19., 37., 28., 3.}} *)

points = Transpose[{Riffle[bins, bins], Flatten[{0, Riffle[counts, counts], 0}]}]

(* => {{0., 0}, {0., 13.}, {2., 13.}, {2., 19.}, {4., 19.}, {4., 37.}, {6., 37.},
{6., 28.}, {8., 28.}, {8., 3.}, {10., 3.}, {10., 0}} *)


Note that it also adds in some zeros to bring the resulting curve down to the axis:

ListLinePlot[points]


Is there a simpler and/or more intuitive way of achieving this behavior?

-
+1, I'm at a complete loss as to how to improve this. Although, I believe Thread may be faster than Transpose for longer lists. – rcollyer Jan 20 '12 at 3:56
You could use ArrayPad[] for starters: Transpose[{Riffle[bins, bins], ArrayPad[Riffle[counts, counts], 1]}] – J. M. Jan 20 '12 at 4:01
Another way: Transpose[{Riffle[bins, bins], Flatten[Partition[counts, 2, 1, {-1, 1}, 0]]}] – J. M. Jan 20 '12 at 4:25
@J.M. Why are you answering in comments?! – Brett Champion Jan 20 '12 at 4:46
@rcollyer I'm not too concerned about speed in this case, but really? I'll have to test that out... – Brett Champion Jan 20 '12 at 4:51

You can use InterpolationOrder for the plot itself to generate the same behavior. I'm assuming here you want the plot you posted in an easier way, not the data handling itself.

{bins, counts} = HistogramList[...];
ListLinePlot[
{bins, Append[counts, 0]} // Transpose,
InterpolationOrder -> 0
]


(You may want to prepend one value to the finished list so that the histogram goes down to zero on the left side as well.)

-
Really clever usage of InterpolationOrder -> 0 ;-) – Vitaliy Kaurov Jan 20 '12 at 4:25
Alternatively: Plot[Evaluate[Piecewise[Transpose[{counts, #1 < t <= #2 & @@@ Partition[bins, 2, 1]}], 0]], {t, First[bins], Last[bins]}, Exclusions -> None]. – J. M. Jan 20 '12 at 4:37

In the same vein as Andy's answer: Differences[ArrayPad[counts, 1]].UnitStep[x - bins] can be used with Plot[]. Apply PiecewiseExpand[] if need be.

-
For those wondering why this works, I gave a mathematical explanation here. – J. M. Jan 26 '12 at 9:36

points = Flatten[Through[{PadLeft, PadRight}[{bins, counts}]], {{3, 1}}]

-
+1 This is awesomely awesome, though unfortunately not intuitive. – Brett Champion Jan 21 '12 at 5:18

Another way of doing it (although, I don't think it fits the "intuitive" part), is:

(Outer[List, {#1}, #2] & @@@
Transpose[{bins,
Partition[ArrayPad[counts, 1], 2, 1, {1, -1}]}]) ~Flatten~ 2


One could also do it using MapIndexed and naïve pairing as

With[{counts1 = ArrayPad[counts, 1]},
MapIndexed[{{#1, First@counts1[[#2]]}, {#1, First@counts1[[#2 + 1]]}} &, bins]
] ~Flatten~ 1

-
That's a creative use of Outer[]. I like! – J. M. Jan 20 '12 at 5:31
Unfortunately this is much slower than Transpose[{Riffle[bins, bins], ArrayPad[Riffle[counts, counts], 1]}] – Mr.Wizard Jan 20 '12 at 9:43
Okay, it's not, but I also don't find this elegant. Sorry. :-/ – Mr.Wizard Jan 20 '12 at 14:25

If you are willing to use Plot instead of ListLinePlot then something like this would work and matches up with the style of the PDF in HistogramDistribution:

f[bins_, counts_][x_] := Boole[Thread[Most[bins] <= x < Rest[bins]]].counts

-
If taking this approach I think it would be better to construct a Piecewise function. – Mr.Wizard Jan 20 '12 at 15:50
Equivalently: Piecewise[Transpose[{counts, Thread[Most[bins] <= x < Rest[bins]]}], 0]. Or maybe even Which @@ Join[Riffle[Thread[Most[bins] <= x < Rest[bins]], counts], {True, 0}]. – J. M. Jan 20 '12 at 15:50

J. M. left a solution in a comment that I really like, so I'm creating an answer out of it:

points = Transpose[{Riffle[bins, bins], ArrayPad[Riffle[counts, counts], 1]}]

-