Iterate through three values stored in two places - ruby

Edited some more. This is a tiny sample of a larger processing piece. My puzzle-solving logic needs to check a one of five attributes for one person against one of five attributes for his four neighbors. This example only shows three. In $hash1, the truth table, rows are people, columns are attributes. We're assuming managing the attributes- I will leave that info out as it's not central to this.
$hash1[2][2] is an 'edge', so it only needs to check against one neighbor, $hash[6][value1]
$hash1[5][2] is a 'middle', so it needs to check against two neighbors, $hash[3][value2] and $hash[9][value2]
The values in $hash1 are 9 for nil, 1 for true, 0 for false
so, in this case, "The man who wears red shirts lives next to the man who drives a Ford"
If we're checking to see if red shirt has been assigned, we need to look through keys 2, 5, 8. When the logic hits $hash1[5][2], and red shirt is 1, logic will check to see if one neighbor is nil and the other has a car which is not a Ford. If true, the nil car gets set to Ford.
$hash1 = {1 => [9,9,9], 2 => [9,9,9], 3 => [9,9,9],
4 => [9,9,9], 5 => [9,1,9], 6 => [9,9,9],
7 => [9,9,9], 8 => [9,9,9], 9 => [9,9,1], 99 => [1,1,1]}
$arry1 = [2,5,8]
$hash2 = { 6 => 99, 3 => 9, 99 => 6}
(entry 99 is there to allow the code to use the same checking mechanism for edges as middles, because if it's the guy on the end, then he only has one neighbor, so if he has a red shirt, his neighbor definitely drives a Ford.)
I need it to loop three times total:
checking 2 and 6 , 99
then 5 and 3 , 9
then 8 and 99 , 6
I have everything working except for looping with the three values from two separate places- I am tinkering with this now-
$arry1.zip($hash2).map(&:flatten).each |key,key2,key3|
Except what it is doing is merging them into this:
<2, 6, 99> <5, 99, 6> <8>
For a longer array, same pattern- the first and last hash pairs come in and get paired with the first two array values, and the rest of the array values are unchanged.

Assuming your code is complete, you should be able to substitute:
val1.each do |key1|
val2.each do |key2,key3|
with
val1.zip(val_2).map(&:flatten).each do |key1, key2, key3|
Additional note: When you're done with solving the problem, post it to codereview.stackexchange.com` so we can do sth with the smell. :)

Related

Place different items evenly in array

I'm wondering if it is possible to somehow "sort" items in an array to place them in "equal" spacings.
An example is more than hundreds of words so:
Apple - 1
Banana - 2
Pineapple - 3
Orange - 4
And this is an array:
[ 'Apple', 'Apple', 'Banana', 'Pineapple', 'Pineapple', 'Pineapple', 'Orange' ]
[ 1, 1, 2, 3, 3, 3, 4 ]
What I want to achieve is something similar to this:
[ 'Apple', 'Pineapple', 'Banana', 'Apple', 'Pineapple', 'Orange', 'Pineapple' ]
[ 1, 3, 2, 1, 3, 4, 3 ]
With this transformation Pineapple has 1 item offset between other 'Pineapple' and Apple is placed in [0] and [3] placement.
Before I start an implementation I'm looking for an already invented solution - it should be something related with standard deviation?
The class of algorithm you're looking for is called multiplexing. A multiplexer takes several input streams, and creates a single output stream, selecting one item at a time from the input. There are many different multiplexing strategies. I'll describe one that's easy to implement, and performs well.
The general idea is that each item has a name, rate, and accumulator, and the item with the largest value in its accumulator is chosen next. In the example given in the question, the rates are 2 for Apple, 1 for Banana, 3 for Pineapple, and 1 for Orange. The sum of the rates is the period, which is 7.
The algorithm operates as follows:
initialize all accumulators to 0
for each slot in one period:
choose the item with the largest accumulator, and add it to the output
update each accumulator by adding the rate to the accumulator
subtract the period from the accumulator of the chosen item
The table below shows how the algorithm progresses. The slots are labelled S1 thru S7. For each slot there are two columns of numbers, the accumulator value for each item, and the adjustment to the accumulator.
In slot 1, the Orange is chosen, so the adjustment to the accumulator is +1 -7 = -6 (add the rate, and subtract the period). For every other item the adjustment is equal to the rate. Notice that all the accumulators start at 0, and return to 0 after the seventh slot. Hence, the algorithm could be run for any number of slots, and it would simply repeat the same pattern.
Name Rate __S1__ __S2__ __S3__ __S4__ __S5__ __S6__ __S7__
Orange 1/7 0 -6 -6 +1 -5 +1 -4 +1 -3 +1 -2 +1 -1 +1 0
Banana 1/7 0 +1 1 +1 2 +1 3 -6 -3 +1 -2 +1 -1 +1 0
Apple 2/7 0 +2 2 +2 4 -5 -1 +2 1 +2 3 -5 -2 +2 0
Pineapple 3/7 0 +3 3 -4 -1 +3 2 +3 5 -4 1 +3 4 -4 0
Selected item: Orange Pine Apple Banana Pine Apple Pine
Here's an implementation in Python:
items = ['Apple', 'Apple', 'Banana', 'Pineapple', 'Pineapple', 'Pineapple', 'Orange']
# Convert the list of items into a list that contains the [name, rate, accumulator]
# for each item. The initial value for the accumulator is 0
counts = {}
for item in items:
counts[item] = counts.get(item, 0) + 1
rates = counts.items()
rates = [[name, rate, 0] for (name, rate) in rates]
rates.sort(key=lambda x:x[1])
# Run the multiplexer, which
# adds the item with the largest accumulator to the output
# updates all the accumulators by adding the rate to the accumulator
# subtracts the period from the chosen accumlator
output = []
period = len(items)
for i in range(period):
best = 0
for j in range(len(rates)):
if rates[j][2] > rates[best][2]: # compare accumulators
best = j
rates[j][2] += rates[j][1] # update accumulator
rates[best][2] -= period
output.append(rates[best][0]) # add an item to the output
print output # ['Orange', 'Pineapple', 'Apple', 'Banana', 'Pineapple', 'Apple', 'Pineapple']
Start off by ordering your words by number of occurences. Then iterate over them, first filling up all even indices, then all odd indices.
The first word can at most fill up all even indices. In most modern arrays there should always be at least as many slots with an even index as there are with an odd one. If your language doesn't qualify for that (i.e. one-based arrays), pick even or odd based on the number of available slots.
The second most common word can only occur at most as many times as the most common word, so there's no possibility this way that the same word winds up in two adjacent slots that way.
A simple python-implementation would look like this:
import math
def spaced_ordering(words):
words = sorted(words, key=words.count, reverse=True)
output = [None] * len(words)
for i in range(0, math.ceil(len(words) / 2)):
output[i * 2] = words[i]
for i in range(0, math.floor(len(words) / 2)):
output[i * 2 + 1] = words[math.ceil(len(words) / 2) + i]
return output
Note: The above implementation is neither exactly performant, nor exactly fancy, nor does it include checking for valid inputs (e.g. what happens if a word occurs more than math.ceil(len(words) / 2) times). It only serves to demonstrate the basic principle.

How to perform range updates in sqrt{n} time?

I have an array and I have to perform query and updates on it.
For queries, I have to find frequency of a particular number in a range from l to r and for update, I have to add x from some range l to r.
How to perform this?
I thought of sqrt{n} optimization but I don't know how to perform range updates with this time complexity.
Edit - Since some people are asking for an example, here is one
Suppose the array is of size n = 8
and it is
1 3 3 4 5 1 2 3
And there are 3 queries to help everybody explain about what I am trying to say
Here they are
q 1 5 3 - This means that you have to find the frequency of 3 in range 1 to 5 which is 2 as 3 appears on 2nd and 3rd position.
second is update query and it goes like this - u 2 4 6 -> This means that you have to add 6 in the array from range 2 to 4. So the new array will become
1 9 9 10 5 1 2 3
And the last query is again the same as first one which will now return 0 as there is no 3 in the array from position 1 to 5 now.
I believe things must be more clear now. :)
I developed this algorithm long time (20+ years) ago for Arithmetic coder.
Both Update and Retrieve are performed in O(log(N)).
I named this algorithm "Method of Intervals". Let I show you the example.
Imagine, we have 8 intervals, with numbers 0-7:
+--0--+--1--+--2-+--3--+--4--+--5--+--6--+--7--+
Lets we create additional set of intervals, each spawns pair of original ones:
+----01-----+----23----+----45-----+----67-----+
Thereafter, we'll create the extra one layer of intervals, spawn pairs of 2nd:
+---------0123---------+---------4567----------+
And at last, we create single interval, covers all 8:
+------------------01234567--------------------+
As you see, in this structure, to retrieve right border of the interval [5], you needed just add together length of intervals [0123] + [45]. to retrieve left border of the interval [5], you needed sum of length the intervals [0123] + [4] (left border for 5 is right border for 4).
Of course, left border of the interval [0] is always = 0.
When you'll watch this proposed structure carefully, you will see, the odd elements in the each layers aren't needed. I say, you do not needed elements 1, 3, 5, 7, 23, 67, 4567, since these elements aren't used, during Retrieval or Update.
Lets we remove the odd elements and make following remuneration:
+--1--+--x--+--3-+--x--+--5--+--x--+--7--+--x--+
+-----2-----+-----x----+-----6-----+-----x-----+
+-----------4----------+-----------x-----------+
+----------------------8-----------------------+
As you see, with this remuneration, used the numbers [1-8]. Lets they will be array indexes. So, you see, there is used memory O(N).
To retrieve right border of the interval [7], you needed add length of the values with indexes 4,6,7. To update length of the interval [7], you needed add difference to all 3 of these values. As result, both Retrieval and Update are performed for Log(N) time.
Now is needed algorithm, how by the original interval number compute set of indexes in this data structure. For instance - how to convert:
1 -> 1
2 -> 2
3 -> 3,2
...
7 -> 7,6,4
This is easy, if we will see binary representation for these numbers:
1 -> 1
10 -> 10
11 -> 11,10
111 -> 111,110,100
As you see, in the each chain - next value is previous value, where rightmost "1" changed to "0". Using simple bit operation "x & (x - 1)", we can wtite a simple loop to iterate array indexes, related to the interval number:
int interval = 7;
do {
int index = interval;
do_something(index);
} while(interval &= interval - 1);

Is it possible to sort a dictionary in Julia?

I have created a dictionary out of two arrays using zip() like
list1 = [1,2,3,4,5]
list2 = [6,7,8,9,19]
dictionary1 = Dict(zip(list1,list2))
Now i want to sort this dictionary by key(list1) or by list2. Can somebody show me a way or function, how to realize it?
Sort also takes a by keyword, which means you can do:
julia> sort(collect(dictionary1), by=x->x[2])
5-element Array{Tuple{Int64,Int64},1}:
(1,6)
(2,7)
(3,8)
(4,9)
(5,19)
Also note that there is a SortedDict in DataStructures.jl, which maintains sort order, and there's an OrderedDict which maintains insertion order. Finally, there's a pull request which would allow direct sorting of OrderedDicts (but I need to finish it up and commit it).
While SortedDict may be useful if it is necessary to keep the dictionary sorted, it is often only necessary to sort the dictionary for output, in which case, the following may be what is required:
list1 = [1,2,3,4,5]
list2 = [6,7,8,9,19]
dictionary1 = Dict(zip(list1,list2))
sort(collect(dictionary1))
... which produces:
5-element Array{(Int64,Int64),1}:
(1,6)
(2,7)
(3,8)
(4,9)
(5,19)
We can sort by values with:
sort(collect(zip(values(dictionary1),keys(dictionary1))))
... which gives:
5-element Array{(Int64,Int64),1}:
(6,1)
(7,2)
(8,3)
(9,4)
(19,5)
The byvalue keyword for the sort function (or sort! for mutating/in place sorting) is useful for sorting dictionaries in order of their values (as opposed to their keys). The result will be of type OrderedDict from OrderedCollections.jl (it's also re-exported by DataStructures.jl).
list1 = [2,1,3,4,5]
list2 = [9,10,8,7,6]
dictionary1 = Dict(zip(list1,list2))
Sort by value (i.e. by list2):
sort(dictionary1; byvalue=true)
Output:
OrderedDict{Int64, Int64} with 5 entries:
5 => 6
4 => 7
3 => 8
2 => 9
1 => 10
Sort by key (i.e. by list1):
sort(dictionary1)
Output:
OrderedDict{Int64, Int64} with 5 entries:
1 => 10
2 => 9
3 => 8
4 => 7
5 => 6

count the number of split points

I just got a question about counting the split points in a integer array, to ensure there is at least one duplicated integer on the two sides.
ex:
1 1 4 2 4 2 4 1
we can either split it into:
1 1 4 2 | 4 2 4 1
or
1 1 4 2 4 | 2 4 1
so that there is at least one '1', '2' ,and '4' are in both sides.
The integer can range from 1 to 100,000
The complexity requires O(n). How to solve this question?
Make one pass over the array and build count[i] = how many times the value i appears in the array. The problem is only solvable if count[i] >= 2 for all non-zero values. You can use this array to tell how many distinct values you have in your array.
Next, make another pass and using another array count2[i] (or you can reuse the first one), keep track of when you have visited each value at least once. Then use that position as your split point.
Example:
1 1 4 2 4 2 4 1
count = [3, 2, 0, 4] => 3 distinct values
1 1 4 2 4 2 4 1
^ => 1 distinct value so far
^ => 1 distinct value so far
^ => 2 distinct values so far
^ => 3 distinct values so far => this is your split point
There might be cases for which there is no solution, for example if the last 1 was at the beginning as well. To detect this, you can just make another pass over the rest of the array after you have decided on the split point and see if you still have all the values on that side.
You can avoid this last pass by using the count and count2 arrays to detect when you can no longer have a split point. This is left as an exercise.

Finding neighbour blocks on a grid

I have a grid like this:
1234567
1 ACBDBAB
2 ABDBABC
3 ABADBAB
4 BABDAAB
5 BABCDBA
6 BDBABCB
7 ABBCBAB
Given a certain coordinate, for example (3:4), I'd like to find all the other
blocks with the same letter that have at least one common side with the original
block and one of those block (recursively). On my example, I'd like the following blocks:
1234567
1 .......
2 .......
3 .......
4 ..B....
5 ..B....
6 ..B....
7 .BB....
My current idea is to check the original column up and down, by incrementing and
decrementing the row number until the letter is different, in my example this
would give me row numbers (4, 5, 6, 7). Then, I increment the
column number and check my previous row numbers, in my example, none of them are
of the original letter, so I start decrementing, I check 4, 5, 6 and 7 at column
2, and I see only 7 matches, so I continue to column 1 and I check row 7 and so
on.
I believe you are looking for the flood fill algorithm.
Edit: I gave some thought to your proposed algorithm and realized why it wouldn't work. The problem is that it only detects convex areas. Say you have a grid like this:
BAB
BBB
BAB
And you would like to replace all the B's with C's. If you started your algorithm from the B in the center of the grid, you'd get this:
BAB
CCC
BAB

Resources