ng-repeat with array of arrays - angularjs

I have dynamic inputData array (length can be between 0 and 10 or 15) that looks something like this:
$scope.inputData = [
[1, 2, 3, 4, 5, 6, 7];
[1, 2, 3, 4, 5, 6, 7];
[1, 2, 3, 4, 5, 6, 7];
[1, 2, 3, 4, 5, 6, 7];
[1, 2, 3, 4, 5, 6, 7];
[1, 2, 3, 4, 5, 6, 7];
]
I need to generate td in the table with ng-repeat so I could have an only first item from each "sub-array" in the first iteration. Then only second item from each "sub-array", etc.. So table should be
th th th th th th
1 1 1 1 1 1
2 2 2 2 2 2
3 3 3 3 3 3
...
And ng repeat should switch indexes in each iteration.
// first iteration:
<td ng-repeat="item in inputData track by $index">{{item[0]}}</td>
// second iteration:
<td ng-repeat="item in inputData track by $index">{{item[1]}}</td>
...
Can I somehow solve this only using ng-repeat or should I sort my arrays in the controller?

Try this:
angular.module('app', []).controller('ctrl', function($scope) {
$scope.inputData = [
[1, 2, 3, 4, 5, 6, 7],
[1, 2, 3, 4, 5, 6, 7],
[1, 2, 3, 4, 5, 6, 7],
[1, 2, 3, 4, 5, 6, 7],
[1, 2, 3, 4, 5, 6, 7],
[1, 2, 3, 4, 5, 6, 7]
]
})
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js">
</script>
<table ng-app='app' ng-controller='ctrl'>
<tbody>
<tr ng-repeat='array in inputData' ng-init='parentIndex=$index'>
<td ng-repeat='item in array'>{{array[parentIndex]}}
<td>
</tr>
</tbody>
</table>

<!DOCTYPE html>
<html ng-app="app">
<head>
<meta charset="utf-8" />
<title>AngularJS Example</title>
<script data-require="angular.js#1.4.x" src="https://code.angularjs.org/1.4.3/angular.js" data-semver="1.4.3"></script>
<script>
var app = angular.module('app', []);
app.controller('MainCtrl', function($scope) {
var items = [
[1, 2, 3, 4, 5, 6, 7],
[1, 2, 3, 4, 5, 6, 7],
[1, 2, 3, 4, 5, 6, 7],
[1, 2, 3, 4, 5, 6, 7],
[1, 2, 3, 4, 5, 6, 7],
[1, 2, 3, 4, 5, 6, 7]
];
$scope.items_transpose = transpose(items);
function transpose(a) {
// Calculate the width and height of the Array
var w = a.length || 0;
var h = a[0] instanceof Array ? a[0].length : 0;
// In case it is a zero matrix, no transpose routine needed.
if(h === 0 || w === 0) { return []; }
/**
* #var {Number} i Counter
* #var {Number} j Counter
* #var {Array} t Transposed data is stored in this array.
*/
var i, j, t = [];
// Loop through every item in the outer array (height)
for(i=0; i<h; i++) {
// Insert a new row (array)
t[i] = [];
// Loop through every item per item in outer array (width)
for(j=0; j<w; j++) {
// Save transposed data.
t[i][j] = a[j][i];
}
}
return t;
}
});
</script>
</head>
<body ng-controller="MainCtrl">
<table>
<tr ng-repeat="item in items_transpose track by $index">
<td ng-repeat="i in item track by $index">{{i}}</td>
</tr>
</table>
</body>
</html>

Related

The truth value of array is ambigous

I have gotten this error a few times in my code and I've never come across it before. Sudoku is a 2d numpy array. Can anyone tell me why and how to fix it?
An example of the sudoku array would be
sudoku = np.array([[0, 2, 4, 7, 6, 3, 5, 9, 1], [3, 9, 7, 4, 5, 0, 8, 2, 6], [8, 5, 6, 9, 2, 0, 0, 4, 7], [0, 8, 9, 5, 3, 6, 7, 1, 4], [7, 3, 1, 2, 9, 4, 6, 5, 8], [6, 4, 5, 8, 1, 7, 9, 3, 2], [4, 7, 2, 3, 8, 9, 1, 6, 5], [9, 1, 8, 6, 4, 5, 2, 7, 3], [5, 6, 3, 1, 7, 2, 4, 8, 9]])
import numpy as np
import copy
global subgrids
sudoku = np.array([[0, 2, 4, 7, 6, 3, 5, 9, 1], [3, 9, 7, 4, 5, 0, 8, 2, 6], [8, 5, 6, 9, 2, 0, 0, 4, 7], [0, 8, 9, 5, 3, 6, 7, 1, 4], [7, 3, 1, 2, 9, 4, 6, 5, 8], [6, 4, 5, 8, 1, 7, 9, 3, 2], [4, 7, 2, 3, 8, 9, 1, 6, 5], [9, 1, 8, 6, 4, 5, 2, 7, 3], [5, 6, 3, 1, 7, 2, 4, 8, 9]])
ad = sudoku.tolist()
frontier = sudoku
subgrids = []
moves = [1,2,3,4,5,6,7,8,9]
columns = []
for i in range(0,9):
columns.append([row[i] for row in sudoku])
def is_possible(sudoku):
for i in range(0, 9):
for j in range(1, 10):
if np.any([ad[i].count(j) > 1] or [columns[i].count(j) > 1]):
return False
return True
sc = copy.deepcopy(ad)
for i in range(0,9,3):
for j in range(0,9,3):
subgrids.append(sc[i][j:j+3]+sc[i+1][j:j+3]+sc[i+2][j:j+3])
def get_next_zero(sudoku):
for i in range(0,9):
for j in range(0,9):
if sudoku[i][j] == 0:
index = [i,j] #i is row index, j is column index
possible_values(index,subgrids)
return True
def is_solution(sudoku):
if is_possible(sudoku) == False:
return False
for i in range(0,9):
for j in range(0,9):
if sudoku[i][j] == 0:
return False
return True
def possible_values(ind,grid):
possible_num = []
row = [a for a in sudoku[ind[0]]]
row = list(row)
column = []
for i in range(0,9):
column.append(sudoku[i][ind[1]])
column = list(column)
if ind[0] < 3:
if ind[1] < 3:
sub = grid[0]
elif 2 < ind[1] < 6:
sub = grid[1]
else:
sub = grid[2]
if 2 < ind[0] < 6:
if ind[1] < 3:
sub = grid[3]
elif 2 < ind[1] < 6:
sub = grid[4]
else:
sub = grid[5]
if ind[0] > 5:
if ind[1] < 3:
sub = grid[6]
elif 2 < ind[1] < 6:
sub = grid[7]
else:
sub = grid[8]
sub = list(sub)
for num in moves:
if num not in row and num not in column and num not in sub:
possible_num.append(num)
solver(possible_num, ind)
def solver(actions, where):
if len(actions) < 1:
np.delete(frontier,len(frontier)-1)
else:
for action in actions:
sudoku[where[0]][where[1]] = action
new_state = sudoku
if is_possible(new_state) == True:
np.append(frontier,new_state)
else:
np.delete(frontier,sudoku)
new_state = frontier.pop()
sudoku_solver(new_state)
def sudoku_solver(sudoku):
if is_possible(sudoku) == False:
print (np.full((9,9),-1))
elif is_solution(sudoku) == True:
print(sudoku)
else:
get_next_zero(sudoku)
sudoku_solver(sudoku)
for num in moves:
if num not in row and num not in column and num not in sub:
possible_num.append(num)
solver(possible_num, ind)
ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()
Another point in the code too
def is_solution(sudoku):
if is_possible(sudoku) == False:
return False
for i in range(0,9):
for j in range(0,9):
if sudoku[i][j] == 0:
return False
return True
ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()

.sort() acting weird with multiple arrays of text and numbers

I have been messing around with the .sort() and .concat() functions trying to combine multiple arrays of numbers and text into one and chronologically order it. It seems to work fine if only numbers are input into the array but as soon as there is text it seems to place it randomly, in this case between 6 and 7. Also, if I remove the number 3 from the array, the number 4 ends up out of order after the text, both being between 9 and 10. I have no idea why it is doing this if anyone could help.
With only numbers:
var multiArray = [[2, 8, 1, 7, 9], [6, 3, 5, 4, 10]];
// returns 1,10,2,3,4,5,6,7,8,9
document.write(multiArray[0]
.concat(multiArray[1])
.sort()
+"<br/>");
// returns 1,2,3,4,5,6,7,8,9,10
document.write(multiArray[0]
.concat(multiArray[1])
.sort((a,b)=>a-b)
+"<br/>");
and with text
var multiArray = [[2, 8, 1, 7, 9], [6, 3, 5, "text", 4, 10]];
// returns 1,2,3,4,5,6,text,7,8,9,10
document.write(multiArray[0]
.concat(multiArray[1])
.sort((a,b)=>a-b)
+"<br/>");
and without 3
var multiArray = [[2, 8, 1, 7, 9], [6, 5, "text", 4, 10]];
// returns 1,2,5,6,7,8,9,text,4,10
document.write(multiArray[0]
.concat(multiArray[1])
.sort((a,b)=>a-b)
+"<br/>");
first, combine all arrays in a single array
var multiArray = [[2, 8, 1, 'foo', 7, '1', 9], [6, 5, 'text', 4, 'bar', 10]];
var flattenArray = [].concat(...multiArray); // [ 2, 8, 1, 'foo', 7, '1', 9, 6, 5, 'text', 4, 'bar', 10 ]
then sort separately numbers and strings
const sortedNumbers = flattenArray
.filter(n => typeof n === 'number')
.sort((a, b) => a - b);
const sortedStrings = flattenArray
.filter(n => typeof n === 'string')
.sort();
finally, concat both
const sorted = sortedNumbers.concat(sortedStrings); // [ 1, 2, 4, 5, 6, 7, 8, 9, 10, '1', 'bar', 'foo', 'text' ]
I assume you want strings after your numbers. Otherwise, simply invert the concatenation:
const sorted = sortedStrings.concat(sortedNumbers);

Split array in groups of n, m, o groups or more

Is there any method to split an array like this?
[1, 2, 3, 4, 5, 6, 7, 8, 9].split(3, 4, 2)
#=> [[1, 2, 3],[4, 5, 6, 7],[8, 9]]
Immutable version with λ:
▶ splitter = ->(array, *parts) do
parts.reduce([[], 0]) do |acc, i|
right = acc.last + i
[acc.first << (acc.last...right), right]
end.first.map { |r| array[r] }
end
#⇒ #<Proc:0x0055ae3d9ae7c8#(pry):18 (lambda)>
▶ splitter.((1..9).to_a, 3, 4, 2)
#⇒ [[1, 2, 3], [4, 5, 6, 7], [8, 9]]
No, there is none, but you can easily write one yourself.
class Array
def in_groups_of_n(*sizes)
sizes.map(&method(:shift))
end
end
Example:
arr = [1, 2, 3, 4, 5, 6, 7, 8, 9]
arr.in_groups_of_n(3, 4, 2)
# => [[1, 2, 3], [4, 5, 6, 7], [8, 9]]
Demonstration
In case you want a none-destructive version, you can use a dup method:
class Array
def in_groups_of_n(*sizes)
duplicate = dup
sizes.map { |size| duplicate.shift(size) }
end
end
arr = [1, 2, 3, 4, 5, 6, 7, 8, 9]
arr.in_groups_of_n(3,4,2)
# => [[1, 2, 3], [4, 5, 6, 7], [8, 9]
arr
# => [1, 2, 3, 4, 5, 6, 7, 8, 9]
Demonstration
Here's a naive Array implementation:
class Array
def multi_split(*sizes)
r = []
e = self.each
sizes.each do |size|
t = []
size.times do
t << e.next
end
r << t
end
r
end
end
p [1, 2, 3, 4, 5, 6, 7, 8, 9].multi_split(3, 4, 2)
# [[1, 2, 3], [4, 5, 6, 7], [8, 9]]
#Stefan mentioned it might make sense to implement it on Enumerable:
module Enumerable
def multi_split(*sizes)
Enumerator.new do |yielder|
e = self.each
sizes.each do |size|
yielder << Array.new(size){ e.next }
end
end
end
end
p [1, 2, 3, 4, 5, 6, 7, 8, 9].multi_split(3, 4, 2).to_a
# [[1, 2, 3], [4, 5, 6, 7], [8, 9]]
Another option (lossless in event the splits are not equal to the array size
def split_at(arr,splits)
rest = arr.last(arr.size - splits.reduce(:+))
enum = arr.to_enum
splits.map do |n|
n.times.map { enum.next }
end.concat(rest.empty? ? [] : [rest])
end
Then called as
split_at (1..9), [3,4,2]
#=> [[1, 2, 3], [4, 5, 6, 7], [8, 9]]
split_at (1..22), [3,4,2]
#=> [[1, 2, 3], [4, 5, 6, 7], [8, 9], [10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22]]
Example
class Array
def split_by_number(*sizes)
sizes.each_with_object([]) { |n,a| a << [a.empty? ? 0 : a.last.sum, n] }.
map { |start, nbr| self[start, nbr] }
end
end
[1, 2, 3, 4, 5, 6, 7, 8, 9].split_by_number 3, 4, 2
#=> [[1, 2, 3], [4, 5, 6, 7], [8, 9]]
Note that
[3, 4, 2].each_with_object([]) { |n,a| a << [a.empty? ? 0 : a.last.sum, n] }
#=> [[0, 3], [3, 4], [7, 2]]

Merge arrays inside of arrays

I have this array:
a = [[1,2,3,4,5],[3,5,6,8,12,45],[3,2,1,5,7,9,10,11],[3,5,6,8,2,1,3,4,6]]
I want to merge its inner arrays so that they become:
a = [[1,2,3,4,5,3,5,6,8,12,45],[3,2,1,5,7,9,10,11,3,5,6,8,2,1,3,4,6]]
How can I do this?
You need to do
a = [
[1, 2, 3, 4, 5],
[3, 5, 6, 8, 12, 45],
[3, 2, 1, 5, 7, 9, 10, 11],
[3, 5, 6, 8, 2, 1, 3, 4, 6]
]
a.each_slice(2).map(&:flatten)
# => [
# [1, 2, 3, 4, 5, 3, 5, 6, 8, 12, 45],
# [3, 2, 1, 5, 7, 9, 10, 11, 3, 5, 6, 8, 2, 1, 3, 4, 6]
# ]
Read the method each_slice(n)
Iterates the given block for each slice of n elements. If no block is given, returns an enumerator.

Removing subsets in array of Sets

Is there an efficient way to remove subsets from an array of sets
E.g. array of arrays
[[2, 3, 4, 7, 8, 9, 10], [1, 5, 6], [3, 7, 10], [4, 8, 9], [5, 6], [7, 10], [8, 9], [6], [9]]
to output an array
[[2, 3, 4, 7, 8, 9, 10], [1, 5, 6]]
The key is guaranteeing the source sets are sorted in descending order of size. That way all supersets precede their subsets.
Here’s a generic function to do it. You could adapt it to take any kind of sequence of sequence of hashable and convert them to an array of sets on the way in:
func removeSubsets<T: Hashable>(source: [Set<T>]) -> [Set<T>] {
let sets = source.sorted { $0.count > $1.count }
var supersets: [Set<T>] = []
for set in sets {
if !contains(supersets, { set.isSubsetOf($0) }) {
supersets.append(set)
}
}
return supersets
}
removeSubsets([[2, 3, 4, 7, 8, 9, 10], [1, 5, 6], [3, 7, 10], [4, 8, 9], [5, 6], [7, 10], [8, 9], [6], [9]])
// returns [{10, 2, 9, 4, 7, 3, 8}, {5, 6, 1}]
It's still cubic unfortunately since contains is linear and so is isSubsetOf.
EDIT: here's the fully generic version:
func removeSubsets
<S0: SequenceType, S1: SequenceType
where S0.Generator.Element == S1,
S1.Generator.Element: Hashable>
(source: S0) -> [Set<S1.Generator.Element>]
{
let sets = map(source) { Set($0) }.sorted { $0.count > $1.count }
var supersets: [Set<S1.Generator.Element>] = []
for set in sets {
if !contains(supersets, { set.isSubsetOf($0) }) {
supersets.append(set)
}
}
return supersets
}
let a: [[Int]] = [
[2, 3, 4, 7, 8, 9, 10],
[1, 5, 6], [3, 7, 10],
[4, 8, 9], [5, 6],
[7, 10], [8, 9],
[6], [9]]
removeSubsets(a) // returns [{10, 2, 9, 4, 7, 3, 8}, {5, 6, 1}]
EDIT2: if you want the result to be an array of the original arrays (since converting them to sets loses their ordering), you could make the following change, which takes more space but is also slightly more efficient since it only converts the supersets to sets, not the subsets:
func removeSubsets<T: Hashable>(source: [[T]]) -> [[T]] {
// note, this is quite efficient since arrays are copy-on-write,
// so it is only really creating a new array of pointers
let sets = source.sorted { $0.count > $1.count }
var supersets: [Set<T>] = []
var result: [[T]] = []
for set in sets {
if !contains(supersets, { $0.isSupersetOf(set) }) {
supersets.append(Set(set))
result.append(set)
}
}
return result
}
removeSubsets([[2, 3, 4, 7, 8, 9, 10], [1, 5, 6], [3, 7, 10], [4, 8, 9], [5, 6], [7, 10], [8, 9], [6], [9]])
// returns [[2, 3, 4, 7, 8, 9, 10], [1, 5, 6]]
EDIT3: if you want to keep the original order of the sets (just with the subsets removed), you could tag them with a number on the way in before sorting, then re-sort them using it and strip it off the result at the end:
func removeSubsets<T: Hashable>(source: [[T]]) -> [[T]] {
let sets = sorted(enumerate(source)) { $0.1.count > $1.1.count }
var supersets: [Set<T>] = []
var result: [(Int,[T])] = []
for (n,set) in sets {
if !contains(supersets, { $0.isSupersetOf(set) }) {
supersets.append(Set(set))
result.append(n,set)
}
}
return result.sorted { $0.0 < $1.0 }.map { $1 }
}
// note, input not sorted in order of length
removeSubsets([[1, 5, 6], [2, 3, 4, 7, 8, 9, 10], [3, 7, 10], [4, 8, 9], [5, 6], [7, 10], [8, 9], [6], [9]])
// returns [[1, 5, 6], [2, 3, 4, 7, 8, 9, 10]]
Just like with any other (non-2D/set) array you could use an array extension like this ...
extension Array
{
func slice(indices:Int...) -> Array
{
var s = indices[0];
var e = self.count - 1;
if (indices.count > 1)
{
e = indices[1];
}
if (e < 0)
{
e += self.count;
}
if (s < 0)
{
s += self.count;
}
let count = (s < e ? e - s : s - e) + 1;
let inc = s < e ? 1 : -1;
var result = Array();
var idx = s;
for i in 0 ..< count
{
result.append(self[idx]);
idx += inc;
}
return result;
}
}
Usage:
let a = [[2, 3, 4, 7, 8, 9, 10], [1, 5, 6], [3, 7, 10], [4, 8, 9], [5, 6], [7, 10], [8, 9], [6], [9]];
let b = a.slice(0, 1);
let c = a.slice(3);
If your array does not contain duplicated int values, you can convert to Set to use some feature from Swift:
(Take a look at Performing Set Operations)
https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/CollectionTypes.html
Here is my code to get another Array which does not contain subsets. This method is not optimized, it works however.
//let arrayOfArray = [[2, 3, 4, 7, 8, 9, 10], [1, 5, 6], [3, 7, 10], [4, 8, 9], [5, 6], [7, 10], [8, 9], [6], [9]]
//use set instead
var setArray : [Set<Int>] = [[2, 3, 4, 7, 8, 9, 10], [1, 5, 6], [3, 7, 10], [4, 8, 9], [5, 6], [7, 10], [8, 9], [6], [9]]
setArray.sort({$0.count > $1.count}) //sort to have ordered array (biggest set at first)
var result = [Set<Int>]() //you will get your result in this variable.
for _aSet in setArray {
var isSubSet = false
for _exitSet in result {
if _aSet.isSubsetOf(_exitSet) {
isSubSet = true
break;
}
}
if (!isSubSet) {
result.append(_aSet)
}
}
This is the most efficient way I could think of:
let nArrays = [[2, 3, 4, 7, 8, 9, 10], [1, 5, 6], [3, 7, 10], [4, 8, 9], [5, 6], [7, 10], [8, 9], [6], [9]]
nArrays
.reduce([Set<Int>]()) {
accu, el in let setEl = Set(el)
return contains(accu) {setEl.isSubsetOf($0)} ? accu : accu + [setEl]
}
//[{10, 2, 9, 4, 7, 3, 8}, {5, 6, 1}]
Instead of checking if every array is a subset of every other array, you just check if they're a subset of the already checked arrays. Of course, that returns an array of Sets, not an array of Arrays, but you can map() over it to convert it back:
let nArrays = [[2, 3, 4, 7, 8, 9, 10], [1, 5, 6], [3, 7, 10], [4, 8, 9], [5, 6], [7, 10], [8, 9], [6], [9]]
nArrays
.reduce([Set<Int>]()) {
accu, el in let setEl = Set(el)
return contains(accu) {setEl.isSubsetOf($0)} ? accu : accu + [setEl]
}
.map{Array($0)}
//[[10, 2, 9, 4, 7, 3, 8], [5, 6, 1]]
You could do this:
let arrayOfArray = [[2, 3, 4, 7, 8, 9, 10], [1, 5, 6], [3, 7, 10], [4, 8, 9], [5, 6], [7, 10], [8, 9], [6], [9]]
let output = arrayOfArray[0...1]

Resources